Repository: lixi5338619/lxBook
Branch: master
Commit: cf485591e68b
Files: 141
Total size: 788.1 KB
Directory structure:
gitextract_1i903oma/
├── .idea/
│ ├── .gitignore
│ ├── crawler-guide-code.iml
│ ├── inspectionProfiles/
│ │ └── profiles_settings.xml
│ ├── misc.xml
│ ├── modules.xml
│ └── vcs.xml
├── readme.md
├── update.txt
├── 第三章:Web Js逆向/
│ ├── 3.10 常见协议分析/
│ │ └── 3.10.2 protobuf协议/
│ │ ├── 3.10.2.1 万方protobuf请求案例/
│ │ │ ├── js3.10.2.1.py
│ │ │ ├── parent_sample.py
│ │ │ ├── s.proto
│ │ │ ├── s_parent_pb2.py
│ │ │ └── s_pb2.py
│ │ └── 3.10.2.2 抖音protobuf解析案例/
│ │ ├── js.py
│ │ ├── s.proto
│ │ ├── s.txt
│ │ └── s_pb2.py
│ ├── 3.11 常见反调试/
│ │ ├── 内存爆破.md
│ │ ├── 开发者工具检测.md
│ │ └── 无限debugger.md
│ ├── 3.13 反混淆AST/
│ │ ├── 3.13.4 用AST还原代码/
│ │ │ ├── ast.js
│ │ │ ├── ast补充/
│ │ │ │ ├── readme.md
│ │ │ │ ├── while-if转变为while-switch.js
│ │ │ │ ├── 三目运算符.js
│ │ │ │ ├── 函数调用处自动替换计算值.js
│ │ │ │ ├── 删除多余的空行和空语句.js
│ │ │ │ ├── 删除所有的代码注释.js
│ │ │ │ ├── 删除未被使用的变量.js
│ │ │ │ ├── 删除未被调用的函数.js
│ │ │ │ ├── 去控制流(for-switch).js
│ │ │ │ ├── 去控制流(while-switch).js
│ │ │ │ ├── 合并定义在object对象外面的key、value.js
│ │ │ │ ├── 处理eval函数.js
│ │ │ │ ├── 处理条件已知的if语句.js
│ │ │ │ ├── 处理条件已知的三元表达式.js
│ │ │ │ ├── 处理没有实参的自执行函数.js
│ │ │ │ ├── 对同一节点使用多个方法.js
│ │ │ │ ├── 条件表达式拆分为if语句.js
│ │ │ │ ├── 构造节点.js
│ │ │ │ ├── 节点类型转换.js
│ │ │ │ ├── 还原Array对象.js
│ │ │ │ ├── 还原object对象.js
│ │ │ │ ├── 还原定义的字面量.js
│ │ │ │ ├── 还原成中文字符.js
│ │ │ │ ├── 还原自执行函数的实参.js
│ │ │ │ └── 逗号表达式.js
│ │ │ ├── for_swith.js
│ │ │ └── lx.js
│ │ └── readme.md
│ ├── 3.3 加密参数定位方法/
│ │ ├── 3.3.7 注入和Hook/
│ │ │ └── readme.md
│ │ └── readme.md
│ ├── 3.4 常见的压缩和混淆/
│ │ ├── 3.4.1 webpack导出/
│ │ │ ├── readme.md
│ │ │ ├── webpack-export.js
│ │ │ ├── 案例一.js
│ │ │ ├── 案例三.js
│ │ │ └── 案例二.js
│ │ └── 3.4.7 lsb隐写/
│ │ └── lsb.py
│ ├── 3.5 常见的编码和加密/
│ │ ├── 3.5.6 AES/
│ │ │ ├── aes_encrypt.js
│ │ │ └── aes_encrypt.py
│ │ └── 3.5.7 RSA/
│ │ ├── rsa_encrypt.js
│ │ └── rsa_encrypt.py
│ ├── 3.6 加密参数还原与模拟/
│ │ ├── 3.6.1 virustotal逆向入门案例/
│ │ │ └── js3.6.1.py
│ │ ├── 3.6.2 newrank榜单逆向案例/
│ │ │ └── js3.6.2.py
│ │ ├── 3.6.3 MD5加密逆向案例/
│ │ │ └── js3.6.3.py
│ │ ├── 3.6.4 RSA参数加密逆向案例/
│ │ │ └── js3.6.4.py
│ │ ├── 3.6.5 AES数据加密逆向案例/
│ │ │ └── run.py
│ │ ├── 3.6.6 AES链接加密逆向案例/
│ │ │ └── js3.6.6/
│ │ │ ├── js3.6.6.py
│ │ │ ├── package.json
│ │ │ └── test.js
│ │ └── 3.6.7 cnvd加速乐分析案例/
│ │ ├── run.py
│ │ ├── t_md5.js
│ │ ├── t_sha1.js
│ │ └── t_sha256.js
│ ├── 3.7 浏览器环境补充/
│ │ ├── 3.7.0 浏览器环境补充/
│ │ │ ├── js-hook.txt
│ │ │ ├── readme.md
│ │ │ ├── t0 浏览器指纹解读.md
│ │ │ ├── t1.js
│ │ │ ├── t2.js
│ │ │ ├── t3.js
│ │ │ ├── t4.js
│ │ │ └── t5补环境框架.md
│ │ ├── 3.7.3 selenium环境模拟/
│ │ │ ├── readme.md
│ │ │ └── test.py
│ │ └── readme.md
│ └── 3.9 加密方法远程调用/
│ ├── 3.9.0 加密方法远程调用/
│ │ ├── readme.md
│ │ └── 头条系web-RPC.md
│ ├── 3.9.1 微博登陆参数RPC/
│ │ ├── client.js
│ │ └── server.py
│ ├── 3.9.2 抖音直播数据RPC/
│ │ ├── 2022-05-25更新.md
│ │ ├── client.js
│ │ ├── readme.md
│ │ └── server.py
│ └── 3.9.3 巨量指数签名RPC/
│ ├── juliang_index20231108.py
│ ├── juliang_index_0.py
│ ├── juliang_index_1.py
│ └── readme.md
├── 第九章:安卓逆向案例/
│ ├── 9.0 书外新增案例/
│ │ ├── cntvnews.md
│ │ ├── readme.md
│ │ ├── 凤凰新闻app.md
│ │ ├── 趣头条sign.md
│ │ └── 飞瓜sign.md
│ ├── 9.1 某新闻加密参数分析和还原/
│ │ └── frida1.py
│ ├── 9.2 某瓣签名Frida还原/
│ │ ├── frida1.py
│ │ └── run.py
│ ├── 9.4 某图参数Frida+Flask RPC/
│ │ └── run.py
│ ├── 9.5 某东加密参数Unidbg生成/
│ │ └── readme.md
│ └── 9.6 某资讯加固脱壳和参数分析/
│ ├── hook.py
│ └── rpc.py
├── 第八章:抓包技巧汇总/
│ ├── heytap软件商店抓包.md
│ ├── readme.md
│ ├── 夜神安卓7导入charles证书.md
│ ├── 快手app抓包.md
│ ├── 抖音app抓包.md
│ ├── 某物app抓包.md
│ └── 点评app抓包案例.md
├── 第六章:安卓逆向/
│ ├── Frida/
│ │ ├── Frida基本方法.md
│ │ ├── Frida自吐算法.js
│ │ ├── Frida自吐算法.py
│ │ └── Frida过Root检测.js
│ ├── Unidbg/
│ │ └── xgorgon.java
│ ├── 常见检测及绕过/
│ │ ├── Frida检测的处理思路.md
│ │ ├── Root检测的处理示例-1.md
│ │ └── 设备环境检测apk.md
│ └── 抖音/
│ └── xposedhook.java
├── 第十一章:反爬虫补充/
│ ├── 11.1 css动态字体反爬/
│ │ └── 选哪儿网动态字体.py
│ ├── 11.2 tls指纹识别/
│ │ ├── aiohttp_ja3.py
│ │ ├── requests_jar3.py
│ │ └── scrapy_Ja3_download.py
│ └── 11.3 http2/
│ └── scrapy_http2_download.py
├── 第十章:验证码识别技术/
│ ├── 10.2.1.1 邮箱滑块验证码.py
│ ├── 10.2.1.2 邮箱滑块验证码.py
│ └── 10.2.2 数美滑块验证码.py
├── 第四章:自动化工具的应用/
│ ├── 4.2.4 Pyppeteer拦截器/
│ │ ├── test.js
│ │ └── test.py
│ ├── 4.3.5 cefpython3爬虫实战/
│ │ └── cefpython_demo.py
│ └── 4.7.3 autojs指数查询案例/
│ ├── main.js
│ └── test.js
└── 附录(一些经验)/
├── readme.md
├── 关于AI逆向.md
├── 检索技巧.md
└── 面试之谈.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .idea/.gitignore
================================================
# Default ignored files
/workspace.xml
================================================
FILE: .idea/crawler-guide-code.iml
================================================
================================================
FILE: .idea/inspectionProfiles/profiles_settings.xml
================================================
================================================
FILE: .idea/misc.xml
================================================
================================================
FILE: .idea/modules.xml
================================================
================================================
FILE: .idea/vcs.xml
================================================
================================================
FILE: readme.md
================================================
# 《爬虫逆向进阶实战》书籍代码库 (视频教程背面扫码!)
书籍内容介绍:http://t.csdn.cn/Y1wsV (视频教程在书背面扫码!)
官方旗舰店:https://item.jd.com/10050499209765.html

## 更新说明
01、(2022-05-23)因为某些在线工具下架了,给大家做了一个:http://cnlans.com/lx/tools
02、(2022-05-25)案例3.9.2,网站调整为wss协议,最新教程和代码已更新。
03、(2022-06-01)案例3.9.3,网站请求接口调整,最新教程和代码已更新。
04、(2022-06-02)新增3.9.0,新增附录,增加书外案例。
05、(2022-06-06)案例更新的代码在本代码库中,更新的视频在b站:[考古学家lx](https://space.bilibili.com/390499740)。
06、(2022-06-12)更新视频教程:[webpack逆向案例一](https://www.bilibili.com/video/BV1QS4y1i7vp?spm_id_from=333.999.0.0)
07、(2022-06-16)更新10.2.1代码。[邮箱滑块验证](https://www.bilibili.com/video/BV1ZB4y1W7nS)
08、(2022-06-18)增加案例 [某图片混淆的滑块协议验证](https://www.bilibili.com/video/BV16L4y1N7kk?)、[某站反调试和加解密](https://www.bilibili.com/video/BV1iB4y1S7Pk?)
09、(2022-07-14)增加第八章及部分内容。
10、(2022-07-23)增加视频教程:[webpack逆向案例二](https://www.bilibili.com/video/BV1Da411M7k7?spm_id_from=333.999.0.0)
11、(2022-07-24)增加视频教程:[webpack逆向案例三](https://www.bilibili.com/video/BV1MB4y1h7nK/?spm_id_from=333.999.0.0)
12、(2026-01-26)在原有目录中增加了一些内容,更新了一些逆向分析工具。
## 加群
可关注 **《pythonlx》公众号** 获取群聊二维码,购书的同学可以扫码背面二维码加客服进入读者群。
代码库中有需要补充的内容可以提Issues或者加群联系我。
python、java、nodejs等环境大家自己安装一下。
# 案例涉及的APK
一些APK的下载链接: https://pan.baidu.com/s/1odDoOh2JKlpF5t7MmH1QJg?pwd=n7ug
# 逆向相关工具
### 查壳反编译
- [查壳小工具](https://pan.baidu.com/s/1s1BoElAyQCnPaxb2T3QpEw?pwd=tmbs)
- [AndroidKiller](https://down.52pojie.cn/Tools/Android_Tools/)
- [Apktools2.5.0](https://pan.baidu.com/s/12qB4N_2Fg-IsTB2BcQuiDw?pwd=gjqs)
- [jadx](https://github.com/skylot/jadx)
- [jadx-gui-ai](https://github.com/cncsnet1/jadx-gui-ai)
- [IDAPro7.0 调试工具Windows版本](https://pan.baidu.com/s/1_-PorRCwHDMpmUI1t_cKcQ?pwd=t39m)
- [ddms](https://pan.baidu.com/s/1wdsZvTA-fAZ12o53Exw80A?pwd=wk3d)
- [JEB3.0中文版](https://pan.baidu.com/s/1kCjw8dP9tq7kLBWkublHag?pwd=k2s4)
- [JEB2.3.7(out)](https://pan.baidu.com/s/1HgyyEomL72jLWY1XMtHv8g?pwd=zpha)
- [超级Jadx(out)](https://pan.baidu.com/s/1SHsJGfnGJJmcPfgcC_lnYA?pwd=9999)
### 脱壳工具
- [FDex2](https://pan.baidu.com/s/1e0zcp1IzA-u7UC-A3gaj8g?pwd=yds2)
- [反射大师](https://pan.baidu.com/s/170oS04qoFdd-Btu9DanHfg?pwd=an39)
- [BlackDex3.1.0](https://pan.baidu.com/s/18gijmyy5dgUCbwi-hnqtpg?pwd=433u)
- [DumpDex](https://github.com/WrBug/dumpDex)
- [FRIDA-DEXDump](https://github.com/hluwa/FRIDA-DEXDump)
### HOOK工具
- [Frida](https://github.com/frida/frida)
- [Xposed](https://pan.baidu.com/s/15WnJD8qj9UzSss55DWLNfA?pwd=7sgb)
- [VAExposed](https://pan.baidu.com/s/1fd0r2fy4mm4jUArGE4MZvA?pwd=mu9q)
- [Inspeckage](https://pan.baidu.com/s/1WfnVM7hKE76jNpQc3FnKWg?pwd=pvcs)
- [SSLUnpinning 20](https://pan.baidu.com/s/1EZuv-JK0a-TLHhw4v6SkvQ?pwd=dsfj)
- [fridaManager](https://pan.baidu.com/s/1u_P2P_kd_H2n2SYTaLB0hA?pwd=jovi)
- [算法助手],作者: 军哥
### 抓包工具
- [httpCanary 安卓抓包工具](https://pan.baidu.com/s/1mdHHaXulnsM6Zxf335yMHA?pwd=tfhx)
- [Postern安卓抓包工具](https://pan.baidu.com/s/1A-2kIVnYSxpgHqiDn4mqnw?pwd=1e5k)
- [Drony_113](https://pan.baidu.com/s/14d6ezZXRWDQayL73d2E8gw?pwd=tyk7)
- [HttpAnalyzerStd V7](https://pan.baidu.com/s/1p3ThL5yqqc5XwTrDdmmGCg?pwd=x9hg)
- [Reqable](https://reqable.com/)
- [Dexterceptor: LSPosed插件-okhttp拦截器](https://github.com/errorman-awful/Dexterceptor)
## chrome插件
- [request-hook](https://pan.baidu.com/s/1OmMiE4rJrTNwarw3EJbz0A?pwd=thyl)
- [Trace-dist](https://github.com/L018/Trace)
- [v_jstools](https://github.com/cilame/v_jstools)
- [AntiDebug Breaker](https://github.com/0xsdeo/AntiDebug_Breaker)
- [油猴-控制台防检测](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)
### 微信小程序
- [UnpackMiniApp](https://pan.baidu.com/s/1dwUehOAnPka9eHjXN6Y-Lg?pwd=unp7)
- [CrackMinApp](https://github.com/Cherrison/CrackMinApp)
# 其他常用工具
- [FontCreator英文版](https://pan.baidu.com/s/1Ek34ePZpJYTkmiCuKsqIMQ?pwd=hnku)
- [鬼鬼JS调试工具](https://pan.baidu.com/s/1hjdgx3DOTJMp0wtYGAa67A?pwd=1s67)
- [MT 管理器](https://pan.baidu.com/s/1AfBDHVvini4bweDOD9GoIw?pwd=9999)
- [NP 管理器](https://pan.baidu.com/s/1X5g8loORq_WS0HLqeasLbg?pwd=9jk7)
- [Autojs](https://pan.baidu.com/s/1bbjFWMjFU5m2RupRyIZcGw?pwd=4ikp)
- [AppSignGet](https://pan.baidu.com/s/1_j2QTVFD6qHP3FKp_FVeCw?pwd=6qmu)
================================================
FILE: update.txt
================================================
## Unable to access ... 443: Timed out
## OpenSSL SSL_connect: Connection was reset in connection to github.com:443
取消全局解决:
git config --global --unset http.proxy
git config --global --unset https.proxy
给pycharm挂上vpn再push
或者当前项目设置代理:(global,local)
git config --local http.proxy 127.0.0.1:15732
git config --local https.proxy 127.0.0.1:15732
## Unable to access xxx OpenSSL SSL_read: Connection was reset, errno 10054
git config --global http.sslBackend "openssl"
---
git config --global -l
================================================
FILE: 第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/js3.10.2.1.py
================================================
{
"currentPage": 1,
"pageSize": 20,
"searchFilter": [0],
"searchScope": 0,
"searchSort": None,
"searchType": "paper",
"searchWord": "lxlx"
}
import s_pb2 as pb
search_request = pb.SearchService.SearchRequest()
search_request.commonrequest.searchType = "paper"
search_request.commonrequest.searchWord = 'lxlx'
search_request.commonrequest.searchScope = 0
search_request.commonrequest.currentPage = 1
search_request.commonrequest.pageSize = 20
search_request.commonrequest.searchFilter.append(0)
bytes_body = search_request.SerializeToString()
bytes_head = bytes([0, 0, 0, 0, len(bytes_body)])
print((bytes_body+bytes_head).decode())
import requests,re
url = 'https://s.wanfangdata.com.cn/SearchService.SearchService/search?'
headers = {
'Content-Type': 'application/grpc-web+proto',
}
resp = requests.post(url=url,data=bytes_head+bytes_body,headers=headers)
print(resp.text)
# 解析可参考 parent_sample.py
================================================
FILE: 第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/parent_sample.py
================================================
# -*- coding: utf-8 -*-
# @Author : lx
# 专利详情页解析示例
import requests
import s_parent_pb2 as pb
from lxpy import copy_headers_dict
parent_id ='ChJQYXRlbnROZXdTMjAyMjAzMjMSEENOMjAyMDEwNjYxNDM1LjYaCGZ6YW1hbTNw'
search_request = pb.SearchService2.CommonRequest()
search_request.resourcetype = "Patent"
search_request.id = parent_id
search_request.referer = ""
search_request.md5id = ""
search_request.transaction = ""
bytes_body = search_request.SerializeToString()
bytes_head = bytes([0, 0, 0, 0, len(bytes_body)])
data=bytes_head+bytes_body
url = 'https://d.wanfangdata.com.cn/Detail.DetailService/getDetailInFormation'
patent_headers = copy_headers_dict('''
accept: */*
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zhq=0.9
cache-control: no-cache
content-type: application/grpc-web+proto
cookies: CASTGC=CASTGCSpecial=
origin: https://d.wanfangdata.com.cn
pragma: no-cache
referer: https://d.wanfangdata.com.cn/patent/ChJQYXRlbnROZXdTMjAyMjAzMjMSEENOMjAyMDEwNjYxNDM1LjYaCGZ6YW1hbTNw
sec-ch-ua: " Not ABrand"v="99", "Chromium"v="99", "Google Chrome"v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-origin
user-agent: Mozilla/5.0 (Windows NT 10.0 Win64 x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36
x-grpc-web: 1
x-user-agent: grpc-web-javascript/0.1
''')
detail_resp = requests.post(url=url,data=data,headers=patent_headers).content
from blackboxprotobuf import protobuf_to_json
import struct,json
data_len = struct.unpack(">i", detail_resp[1:5])[0]
data = json.loads(protobuf_to_json(detail_resp[5: 5 + data_len])[0])['1']['5']
print(data)
================================================
FILE: 第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/s.proto
================================================
syntax = "proto3";
message SearchService {
enum SearchScope {
A = 0;
}
enum SearchFilter {
B = 0;
}
message CommonRequest {
string searchType = 1;
string searchWord = 2;
int32 currentPage = 3;
int32 pageSize = 4;
SearchScope searchScope = 5;
repeated SearchFilter searchFilter = 6;
}
message SearchRequest {
CommonRequest commonrequest = 1;
}
}
================================================
FILE: 第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/s_parent_pb2.py
================================================
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: s_parent.proto
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='s_parent.proto',
package='',
syntax='proto3',
serialized_options=None,
create_key=_descriptor._internal_create_key,
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'
)
_SEARCHSERVICE2_COMMONREQUEST = _descriptor.Descriptor(
name='CommonRequest',
full_name='SearchService2.CommonRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='resourcetype', full_name='SearchService2.CommonRequest.resourcetype', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='id', full_name='SearchService2.CommonRequest.id', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='referer', full_name='SearchService2.CommonRequest.referer', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='md5id', full_name='SearchService2.CommonRequest.md5id', index=3,
number=4, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='transaction', full_name='SearchService2.CommonRequest.transaction', index=4,
number=5, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=37,
serialized_end=139,
)
_SEARCHSERVICE2_SEARCHREQUEST = _descriptor.Descriptor(
name='SearchRequest',
full_name='SearchService2.SearchRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='commonrequest', full_name='SearchService2.SearchRequest.commonrequest', index=0,
number=1, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=141,
serialized_end=210,
)
_SEARCHSERVICE2 = _descriptor.Descriptor(
name='SearchService2',
full_name='SearchService2',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
],
extensions=[
],
nested_types=[_SEARCHSERVICE2_COMMONREQUEST, _SEARCHSERVICE2_SEARCHREQUEST, ],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=19,
serialized_end=210,
)
_SEARCHSERVICE2_COMMONREQUEST.containing_type = _SEARCHSERVICE2
_SEARCHSERVICE2_SEARCHREQUEST.fields_by_name['commonrequest'].message_type = _SEARCHSERVICE2_COMMONREQUEST
_SEARCHSERVICE2_SEARCHREQUEST.containing_type = _SEARCHSERVICE2
DESCRIPTOR.message_types_by_name['SearchService2'] = _SEARCHSERVICE2
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
SearchService2 = _reflection.GeneratedProtocolMessageType('SearchService2', (_message.Message,), {
'CommonRequest' : _reflection.GeneratedProtocolMessageType('CommonRequest', (_message.Message,), {
'DESCRIPTOR' : _SEARCHSERVICE2_COMMONREQUEST,
'__module__' : 's_parent_pb2'
# @@protoc_insertion_point(class_scope:SearchService2.CommonRequest)
})
,
'SearchRequest' : _reflection.GeneratedProtocolMessageType('SearchRequest', (_message.Message,), {
'DESCRIPTOR' : _SEARCHSERVICE2_SEARCHREQUEST,
'__module__' : 's_parent_pb2'
# @@protoc_insertion_point(class_scope:SearchService2.SearchRequest)
})
,
'DESCRIPTOR' : _SEARCHSERVICE2,
'__module__' : 's_parent_pb2'
# @@protoc_insertion_point(class_scope:SearchService2)
})
_sym_db.RegisterMessage(SearchService2)
_sym_db.RegisterMessage(SearchService2.CommonRequest)
_sym_db.RegisterMessage(SearchService2.SearchRequest)
# @@protoc_insertion_point(module_scope)
================================================
FILE: 第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/s_pb2.py
================================================
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: s.proto
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='s.proto',
package='',
syntax='proto3',
serialized_options=None,
create_key=_descriptor._internal_create_key,
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'
)
_SEARCHSERVICE_SEARCHSCOPE = _descriptor.EnumDescriptor(
name='SearchScope',
full_name='SearchService.SearchScope',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='A', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=296,
serialized_end=316,
)
_sym_db.RegisterEnumDescriptor(_SEARCHSERVICE_SEARCHSCOPE)
_SEARCHSERVICE_SEARCHFILTER = _descriptor.EnumDescriptor(
name='SearchFilter',
full_name='SearchService.SearchFilter',
filename=None,
file=DESCRIPTOR,
create_key=_descriptor._internal_create_key,
values=[
_descriptor.EnumValueDescriptor(
name='B', index=0, number=0,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
serialized_start=318,
serialized_end=339,
)
_sym_db.RegisterEnumDescriptor(_SEARCHSERVICE_SEARCHFILTER)
_SEARCHSERVICE_COMMONREQUEST = _descriptor.Descriptor(
name='CommonRequest',
full_name='SearchService.CommonRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='searchType', full_name='SearchService.CommonRequest.searchType', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='searchWord', full_name='SearchService.CommonRequest.searchWord', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='currentPage', full_name='SearchService.CommonRequest.currentPage', index=2,
number=3, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='pageSize', full_name='SearchService.CommonRequest.pageSize', index=3,
number=4, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='searchScope', full_name='SearchService.CommonRequest.searchScope', index=4,
number=5, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='searchFilter', full_name='SearchService.CommonRequest.searchFilter', index=5,
number=6, type=14, cpp_type=8, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=30,
serialized_end=224,
)
_SEARCHSERVICE_SEARCHREQUEST = _descriptor.Descriptor(
name='SearchRequest',
full_name='SearchService.SearchRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='commonrequest', full_name='SearchService.SearchRequest.commonrequest', index=0,
number=1, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=226,
serialized_end=294,
)
_SEARCHSERVICE = _descriptor.Descriptor(
name='SearchService',
full_name='SearchService',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
],
extensions=[
],
nested_types=[_SEARCHSERVICE_COMMONREQUEST, _SEARCHSERVICE_SEARCHREQUEST, ],
enum_types=[
_SEARCHSERVICE_SEARCHSCOPE,
_SEARCHSERVICE_SEARCHFILTER,
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=12,
serialized_end=339,
)
_SEARCHSERVICE_COMMONREQUEST.fields_by_name['searchScope'].enum_type = _SEARCHSERVICE_SEARCHSCOPE
_SEARCHSERVICE_COMMONREQUEST.fields_by_name['searchFilter'].enum_type = _SEARCHSERVICE_SEARCHFILTER
_SEARCHSERVICE_COMMONREQUEST.containing_type = _SEARCHSERVICE
_SEARCHSERVICE_SEARCHREQUEST.fields_by_name['commonrequest'].message_type = _SEARCHSERVICE_COMMONREQUEST
_SEARCHSERVICE_SEARCHREQUEST.containing_type = _SEARCHSERVICE
_SEARCHSERVICE_SEARCHSCOPE.containing_type = _SEARCHSERVICE
_SEARCHSERVICE_SEARCHFILTER.containing_type = _SEARCHSERVICE
DESCRIPTOR.message_types_by_name['SearchService'] = _SEARCHSERVICE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
SearchService = _reflection.GeneratedProtocolMessageType('SearchService', (_message.Message,), {
'CommonRequest' : _reflection.GeneratedProtocolMessageType('CommonRequest', (_message.Message,), {
'DESCRIPTOR' : _SEARCHSERVICE_COMMONREQUEST,
'__module__' : 's_pb2'
# @@protoc_insertion_point(class_scope:SearchService.CommonRequest)
})
,
'SearchRequest' : _reflection.GeneratedProtocolMessageType('SearchRequest', (_message.Message,), {
'DESCRIPTOR' : _SEARCHSERVICE_SEARCHREQUEST,
'__module__' : 's_pb2'
# @@protoc_insertion_point(class_scope:SearchService.SearchRequest)
})
,
'DESCRIPTOR' : _SEARCHSERVICE,
'__module__' : 's_pb2'
# @@protoc_insertion_point(class_scope:SearchService)
})
_sym_db.RegisterMessage(SearchService)
_sym_db.RegisterMessage(SearchService.CommonRequest)
_sym_db.RegisterMessage(SearchService.SearchRequest)
# @@protoc_insertion_point(module_scope)
================================================
FILE: 第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.2 抖音protobuf解析案例/js.py
================================================
from google.protobuf.json_format import MessageToDict
from s_pb2 import *
import base64
def on_message(data):
danmu_resp = test()
danmu_resp.ParseFromString(data)
Message = MessageToDict(danmu_resp, preserving_proto_field_name=True)
for message in Message["message"]:
method = message["method"]
payload = bytes(base64.b64decode(message["payload"].encode()))
if method == "WebcastMemberMessage":
menber_message = WebcastMemberMessage()
menber_message.ParseFromString(payload)
mes= MessageToDict(menber_message, preserving_proto_field_name=True)
print(mes)
elif method == "WebcastLikeMessage":
menber_message = WebcastLikeMessage()
menber_message.ParseFromString(payload)
mes = MessageToDict(menber_message, preserving_proto_field_name=True)
print(mes)
with open('s.txt','rb') as f:
data = f.read()
on_message(data)
================================================
FILE: 第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.2 抖音protobuf解析案例/s.proto
================================================
syntax = "proto3";
message test{
repeated Message message =1;
string cursor =2;
uint64 fetchInterval=3;
uint64 now=4;
string internalExt=5;
int32 fetchType=6;
}
message Message{
string method=1;
bytes payload=2;
uint64 msgId=3;
int32 msgType=4;
uint64 offset=5;
int64 rankScore = 7;
int64 topUserNo = 8;
int64 enterType = 9;
int64 action = 10;
int64 userId = 12;
string popStr = 14;
}
message WebcastMemberMessage{
repeated Common common=1;
repeated User user=2;
uint64 memberCount=3;
repeated User operator=4;
bool isSetToAdmin=5;
bool isTopUser=6;
}
message WebcastLikeMessage{
repeated Common common=1;
uint64 count=2;
uint64 total=3;
uint64 color=4;
repeated User user=5;
string icon=6;
}
message WebcastChatMessage{
repeated Common common=1;
repeated User user=2;
string content=3;
bool visibleToSender = 4;
string fullScreenTextColor = 6;
}
message WebcastGiftMessage{
repeated Common common=1;
uint64 giftId=2;
uint64 fanTicketCount=3;
uint64 groupCount=4;
uint64 repeatCount=5;
uint64 comboCount=6;
repeated User user=7;
repeated User toUser=8;
}
message Common{
string method=1;
uint64 msgId=2;
uint64 roomId=3;
uint64 createTime=4;
int32 monitor=5;
bool isShowMsg=6;
string describe=7;
uint64 foldType=9;
}
message User{
int64 id = 1;
int64 shortId = 2;
string nickname = 3;
int32 gender = 4;
string signature = 5;
int32 level = 6;
int64 birthday = 7;
string telephone = 8;
bool verified = 12;
int32 experience = 13;
string city = 14;
int32 status = 15;
int64 createTime = 16;
int64 modifyTime = 17;
int32 secret = 18;
string shareQrcodeUri = 19;
int32 incomeSharePercent = 20;
}
================================================
FILE: 第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.2 抖音protobuf解析案例/s_pb2.py
================================================
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: s.proto
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='s.proto',
package='',
syntax='proto3',
serialized_options=None,
create_key=_descriptor._internal_create_key,
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'
)
_TEST = _descriptor.Descriptor(
name='test',
full_name='test',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='message', full_name='test.message', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='cursor', full_name='test.cursor', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='fetchInterval', full_name='test.fetchInterval', index=2,
number=3, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='now', full_name='test.now', index=3,
number=4, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='internalExt', full_name='test.internalExt', index=4,
number=5, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='fetchType', full_name='test.fetchType', index=5,
number=6, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=11,
serialized_end=136,
)
_MESSAGE = _descriptor.Descriptor(
name='Message',
full_name='Message',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='method', full_name='Message.method', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='payload', full_name='Message.payload', index=1,
number=2, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=b"",
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='msgId', full_name='Message.msgId', index=2,
number=3, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='msgType', full_name='Message.msgType', index=3,
number=4, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='offset', full_name='Message.offset', index=4,
number=5, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='rankScore', full_name='Message.rankScore', index=5,
number=7, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='topUserNo', full_name='Message.topUserNo', index=6,
number=8, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='enterType', full_name='Message.enterType', index=7,
number=9, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='action', full_name='Message.action', index=8,
number=10, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='userId', full_name='Message.userId', index=9,
number=12, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='popStr', full_name='Message.popStr', index=10,
number=14, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=139,
serialized_end=334,
)
_WEBCASTMEMBERMESSAGE = _descriptor.Descriptor(
name='WebcastMemberMessage',
full_name='WebcastMemberMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='common', full_name='WebcastMemberMessage.common', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='user', full_name='WebcastMemberMessage.user', index=1,
number=2, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='memberCount', full_name='WebcastMemberMessage.memberCount', index=2,
number=3, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='operator', full_name='WebcastMemberMessage.operator', index=3,
number=4, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='isSetToAdmin', full_name='WebcastMemberMessage.isSetToAdmin', index=4,
number=5, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='isTopUser', full_name='WebcastMemberMessage.isTopUser', index=5,
number=6, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=337,
serialized_end=492,
)
_WEBCASTLIKEMESSAGE = _descriptor.Descriptor(
name='WebcastLikeMessage',
full_name='WebcastLikeMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='common', full_name='WebcastLikeMessage.common', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='count', full_name='WebcastLikeMessage.count', index=1,
number=2, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='total', full_name='WebcastLikeMessage.total', index=2,
number=3, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='color', full_name='WebcastLikeMessage.color', index=3,
number=4, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='user', full_name='WebcastLikeMessage.user', index=4,
number=5, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='icon', full_name='WebcastLikeMessage.icon', index=5,
number=6, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=494,
serialized_end=619,
)
_WEBCASTCHATMESSAGE = _descriptor.Descriptor(
name='WebcastChatMessage',
full_name='WebcastChatMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='common', full_name='WebcastChatMessage.common', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='user', full_name='WebcastChatMessage.user', index=1,
number=2, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='content', full_name='WebcastChatMessage.content', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='visibleToSender', full_name='WebcastChatMessage.visibleToSender', index=3,
number=4, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='fullScreenTextColor', full_name='WebcastChatMessage.fullScreenTextColor', index=4,
number=6, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=622,
serialized_end=759,
)
_WEBCASTGIFTMESSAGE = _descriptor.Descriptor(
name='WebcastGiftMessage',
full_name='WebcastGiftMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='common', full_name='WebcastGiftMessage.common', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='giftId', full_name='WebcastGiftMessage.giftId', index=1,
number=2, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='fanTicketCount', full_name='WebcastGiftMessage.fanTicketCount', index=2,
number=3, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='groupCount', full_name='WebcastGiftMessage.groupCount', index=3,
number=4, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='repeatCount', full_name='WebcastGiftMessage.repeatCount', index=4,
number=5, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='comboCount', full_name='WebcastGiftMessage.comboCount', index=5,
number=6, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='user', full_name='WebcastGiftMessage.user', index=6,
number=7, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='toUser', full_name='WebcastGiftMessage.toUser', index=7,
number=8, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=762,
serialized_end=952,
)
_COMMON = _descriptor.Descriptor(
name='Common',
full_name='Common',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='method', full_name='Common.method', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='msgId', full_name='Common.msgId', index=1,
number=2, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='roomId', full_name='Common.roomId', index=2,
number=3, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='createTime', full_name='Common.createTime', index=3,
number=4, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='monitor', full_name='Common.monitor', index=4,
number=5, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='isShowMsg', full_name='Common.isShowMsg', index=5,
number=6, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='describe', full_name='Common.describe', index=6,
number=7, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='foldType', full_name='Common.foldType', index=7,
number=9, type=4, cpp_type=4, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=955,
serialized_end=1102,
)
_USER = _descriptor.Descriptor(
name='User',
full_name='User',
filename=None,
file=DESCRIPTOR,
containing_type=None,
create_key=_descriptor._internal_create_key,
fields=[
_descriptor.FieldDescriptor(
name='id', full_name='User.id', index=0,
number=1, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='shortId', full_name='User.shortId', index=1,
number=2, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='nickname', full_name='User.nickname', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='gender', full_name='User.gender', index=3,
number=4, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='signature', full_name='User.signature', index=4,
number=5, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='level', full_name='User.level', index=5,
number=6, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='birthday', full_name='User.birthday', index=6,
number=7, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='telephone', full_name='User.telephone', index=7,
number=8, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='verified', full_name='User.verified', index=8,
number=12, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='experience', full_name='User.experience', index=9,
number=13, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='city', full_name='User.city', index=10,
number=14, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='status', full_name='User.status', index=11,
number=15, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='createTime', full_name='User.createTime', index=12,
number=16, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='modifyTime', full_name='User.modifyTime', index=13,
number=17, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='secret', full_name='User.secret', index=14,
number=18, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='shareQrcodeUri', full_name='User.shareQrcodeUri', index=15,
number=19, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=b"".decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
name='incomeSharePercent', full_name='User.incomeSharePercent', index=16,
number=20, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=1105,
serialized_end=1421,
)
_TEST.fields_by_name['message'].message_type = _MESSAGE
_WEBCASTMEMBERMESSAGE.fields_by_name['common'].message_type = _COMMON
_WEBCASTMEMBERMESSAGE.fields_by_name['user'].message_type = _USER
_WEBCASTMEMBERMESSAGE.fields_by_name['operator'].message_type = _USER
_WEBCASTLIKEMESSAGE.fields_by_name['common'].message_type = _COMMON
_WEBCASTLIKEMESSAGE.fields_by_name['user'].message_type = _USER
_WEBCASTCHATMESSAGE.fields_by_name['common'].message_type = _COMMON
_WEBCASTCHATMESSAGE.fields_by_name['user'].message_type = _USER
_WEBCASTGIFTMESSAGE.fields_by_name['common'].message_type = _COMMON
_WEBCASTGIFTMESSAGE.fields_by_name['user'].message_type = _USER
_WEBCASTGIFTMESSAGE.fields_by_name['toUser'].message_type = _USER
DESCRIPTOR.message_types_by_name['test'] = _TEST
DESCRIPTOR.message_types_by_name['Message'] = _MESSAGE
DESCRIPTOR.message_types_by_name['WebcastMemberMessage'] = _WEBCASTMEMBERMESSAGE
DESCRIPTOR.message_types_by_name['WebcastLikeMessage'] = _WEBCASTLIKEMESSAGE
DESCRIPTOR.message_types_by_name['WebcastChatMessage'] = _WEBCASTCHATMESSAGE
DESCRIPTOR.message_types_by_name['WebcastGiftMessage'] = _WEBCASTGIFTMESSAGE
DESCRIPTOR.message_types_by_name['Common'] = _COMMON
DESCRIPTOR.message_types_by_name['User'] = _USER
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
test = _reflection.GeneratedProtocolMessageType('test', (_message.Message,), {
'DESCRIPTOR' : _TEST,
'__module__' : 's_pb2'
# @@protoc_insertion_point(class_scope:test)
})
_sym_db.RegisterMessage(test)
Message = _reflection.GeneratedProtocolMessageType('Message', (_message.Message,), {
'DESCRIPTOR' : _MESSAGE,
'__module__' : 's_pb2'
# @@protoc_insertion_point(class_scope:Message)
})
_sym_db.RegisterMessage(Message)
WebcastMemberMessage = _reflection.GeneratedProtocolMessageType('WebcastMemberMessage', (_message.Message,), {
'DESCRIPTOR' : _WEBCASTMEMBERMESSAGE,
'__module__' : 's_pb2'
# @@protoc_insertion_point(class_scope:WebcastMemberMessage)
})
_sym_db.RegisterMessage(WebcastMemberMessage)
WebcastLikeMessage = _reflection.GeneratedProtocolMessageType('WebcastLikeMessage', (_message.Message,), {
'DESCRIPTOR' : _WEBCASTLIKEMESSAGE,
'__module__' : 's_pb2'
# @@protoc_insertion_point(class_scope:WebcastLikeMessage)
})
_sym_db.RegisterMessage(WebcastLikeMessage)
WebcastChatMessage = _reflection.GeneratedProtocolMessageType('WebcastChatMessage', (_message.Message,), {
'DESCRIPTOR' : _WEBCASTCHATMESSAGE,
'__module__' : 's_pb2'
# @@protoc_insertion_point(class_scope:WebcastChatMessage)
})
_sym_db.RegisterMessage(WebcastChatMessage)
WebcastGiftMessage = _reflection.GeneratedProtocolMessageType('WebcastGiftMessage', (_message.Message,), {
'DESCRIPTOR' : _WEBCASTGIFTMESSAGE,
'__module__' : 's_pb2'
# @@protoc_insertion_point(class_scope:WebcastGiftMessage)
})
_sym_db.RegisterMessage(WebcastGiftMessage)
Common = _reflection.GeneratedProtocolMessageType('Common', (_message.Message,), {
'DESCRIPTOR' : _COMMON,
'__module__' : 's_pb2'
# @@protoc_insertion_point(class_scope:Common)
})
_sym_db.RegisterMessage(Common)
User = _reflection.GeneratedProtocolMessageType('User', (_message.Message,), {
'DESCRIPTOR' : _USER,
'__module__' : 's_pb2'
# @@protoc_insertion_point(class_scope:User)
})
_sym_db.RegisterMessage(User)
# @@protoc_insertion_point(module_scope)
================================================
FILE: 第三章:Web Js逆向/3.11 常见反调试/内存爆破.md
================================================
# 内存爆破
在使用浏览器控制台(如 Chrome DevTools)或本地环境 调试 JavaScript 代码时,有时会遇到“内存爆破”(Memory Spike 或 Out of Memory)的问题。这通常发生在执行大量数据操作、递归调用、或在控制台中打印大型对象时。
---
## 一、什么是内存爆破
**内存爆破**指的是 JavaScript 执行过程中,占用的内存突然激增,导致浏览器卡顿、崩溃或抛出 `Out of Memory` 错误。在控制台中调试时,常见的表现包括:
* 控制台输出大量数据(如大型数组、对象)
* 递归函数未正确终止
* 数据结构存在循环引用
* 持续创建未释放的对象或闭包
---
## 二、常见原因和解决方案
### 1.开启控制台后内存溢出
开启devtools后,调试过程中出现内存爆炸的情况,通常是站点的反调试机制。
**方案**:在内存上涨时,点击控制台调试位置的暂停按钮。等自动跳转到对应代码位置后,分析检测点和溢出点,找到后可删除并覆盖对应JS代码。
### 2. 控制台打印大型对象
在控制台中直接打印大型对象(如 DOM 元素、大型数组、嵌套对象)会导致浏览器尝试将其结构完整加载到内存中进行渲染,从而引发内存激增。
```javascript
console.log(largeData); // largeData 是一个包含数百万条数据的对象或数组
```
**方案**:避免直接打印大型对象
* 只打印关键字段或摘要信息
* 使用 `console.table()` 替代 `console.log()` 来查看结构化数据
* 使用 `JSON.stringify()` 限制打印深度
```javascript
console.log(JSON.stringify(largeData, null, 2).substring(0, 1000)); // 只打印前1000字符
```
* 使用 `slice()` 截取部分数组
```javascript
console.log(largeArray.slice(0, 100)); // 只打印前100项
```
### 3. 递归调用未终止
无限递归会不断压栈,最终导致内存溢出。
```javascript
function infiniteRecursion() {
console.log("Calling...");
infiniteRecursion();
}
infiniteRecursion(); // 会爆栈并导致内存问题
```
**方案**:避免无限递归和深度递归
* 增加递归终止条件
* 使用尾递归优化(ES6 支持)
* 改用循环结构替代递归
### 4. 内存泄漏(Memory Leak)
* 未释放的闭包引用
* 未清理的事件监听器
* 缓存机制不当
**方案**:使用 DevTools 内存分析工具
Chrome DevTools 提供了强大的内存分析工具,可用于:
* 查看内存快照(Memory Snapshot)
* 检测内存泄漏(Memory Leak Detection)
* 跟踪对象保留树(Retaining Tree)
路径:`DevTools -> Memory -> Take Snapshot`
### 5. 数据结构存在循环引用
在打印或序列化对象时,如果对象存在循环引用,可能导致无限递归或大量内存占用。
```javascript
let obj = {};
obj.self = obj;
console.log(obj); // 控制台可能卡死或占用大量内存
```
**方案**:清理不必要的引用
* 及时将不再使用的对象设为 `null`
* 移除事件监听器
* 使用弱引用(如 `WeakMap`、`WeakSet`)存储临时数据
```javascript
let cache = new WeakMap();
function processElement(el) {
cache.set(el, "processed");
}
```
### 6. 使用 `eval` 或动态代码执行
某些调试技巧使用 `eval()` 执行字符串代码,可能导致不可预测的内存行为。
**方案**:避免控制台中频繁执行大型脚本
* 将调试逻辑封装到函数中,避免在控制台中直接运行复杂逻辑
* 使用断点替代 `console.log()` 进行变量查看
### 7. 使用 `try...catch` 捕获异常
防止内存异常导致脚本崩溃:
```javascript
try {
// 大型数据处理
} catch (e) {
console.error("内存错误:", e);
}
```
---
================================================
FILE: 第三章:Web Js逆向/3.11 常见反调试/开发者工具检测.md
================================================
# 开发者工具检测
浏览器按 F12 后打开的工具,正式名称是 **开发者工具(Developer Tools,简称 DevTools)**,也常被称作「调试工具」「F12 工具」。
检测原理可以参考 "开发者工具检测器":[https://github.com/AEPKILL/devtools-detector](https://github.com/AEPKILL/devtools-detector)
针对检测器,一个通用的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)
启用后可通过 [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**检测机制。

================================================
FILE: 第三章:Web Js逆向/3.11 常见反调试/无限debugger.md
================================================
# 无限debugger
`debugger` 是JavaScript中的一个关键字,用于在代码中设置断点。当浏览器的开发者工具开启时,遇到 `debugger` 语句会暂停代码执行,等待用户操作。
**无限** `**debugger**` **的表现:**
* 控制台频繁弹出断点提示
* 页面无法正常加载或执行
* 手动跳过断点后又立即再次触发
**示例代码:**
```javascript
setInterval(function() {
debugger;
}, 1000);
```
或者更隐蔽的方式:
```javascript
function loopDebug() {
while (true) {
debugger;
}
}
loopDebug();
```
---
## 三、绕过无限 `debugger` 的方法
### 方法一:禁用所有断点
**Chrome / Edge / Firefox 浏览器:**
1. 打开开发者工具(F12)
2. 在“Sources”或“Debugger”面板中找到“Deactivate breakpoints”按钮(通常是一个断点图标或“暂停”图标)
3. 点击按钮(或使用快捷键 `Ctrl + F8` / `Cmd + F8`),禁用所有断点
> 此方法可以临时跳过所有断点,包括 `debugger` 语句。
---
### 方法二:覆盖 `debugger` 语句(控制台注入代码)
由于 `debugger` 是语言关键字,不能直接覆盖。但可以尝试使用调试器忽略断点执行:
1. 打开开发者工具
2. 在“Sources”面板找到触发 `debugger` 的脚本
3. 在 `debugger` 行号左侧点击,取消该行的断点
4. 或者右键选择“Never pause here”(Chrome)
---
### 方法三:使用“黑盒脚本”功能(Blackboxing)
**Chrome / Edge 支持此功能:**
1. 打开开发者工具
2. 点击右上角“三个点”菜单 > “Settings”
3. 进入 “Debugger” 或 “Blackboxing” 选项卡
4. 添加你想忽略调试的脚本文件或使用正则匹配
5. 浏览器将不再在这些文件中暂停(包括 `debugger`)
> 适用于已知触发无限 `debugger` 的脚本文件路径。
---
### 方法四:使用浏览器扩展绕过
可以使用浏览器插件来自动屏蔽某些脚本或修改网页行为:
* **Tampermonkey:** 自定义hook脚本
* **uBlock Origin:**屏蔽特定脚本加载
* **Debugger Auto Continue**:自动跳过断点
* **AntiBebug Breaker**: 绕过无限Debugger
**示例:使用 Tampermonkey 脚本跳过** `**debugger**`
```javascript
// ==UserScript==
// @name Skip Debugger
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 跳过无限 debugger
// @author You
// @match *://*/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 覆盖 setInterval(可选)
const origSetInterval = window.setInterval;
window.setInterval = function(func, delay) {
if (func.toString().includes("debugger")) {
console.log("Blocked setInterval with debugger");
return null;
}
return origSetInterval.apply(this, arguments);
};
// 其他绕过方式可继续添加
})();
```
---
**示例:hook Function 原型构造函数, 修改debugger**
```javascript
Function.prototype.temp_constructor= Function.prototype.constructor;
Function.prototype.constructor=function(){
if (arguments && typeof arguments[0]==="string"){
if (arguments[0]==="debugger")
return ""
}
return Function.prototype.temp_constructor.apply(this, arguments);
};
// hook setInterval 定时器函数 替换debugger
_setInterval = setInterval
setInterval = function setInterval(code, time){
console.log(code, time)
code = code.toString().replace(/debugger/, "").replace(/function ()/, "function xxx")
return _setInterval(new Function(code) , time)
}
_setTimeout = setTimeout
setTimeout = function setTimeout(code, time){
console.log(code, time)
code = code.toString().replace(/debugger/, "").replace(/function ()/, "function xxx")
return _setTimeout(new Function(code), time)
}
```
---
### 方法五:使用火狐浏览器(推荐)
使用新版firefox浏览器,选中debugger代码行,取消勾选【在调试语句上暂停】
---
## 五、总结
| 方法 | 说明 | 适用场景 |
| --- | --- | --- |
| 禁用所有断点 | 快速跳过所有断点 | 临时调试 |
| 黑盒脚本 | 忽略特定文件的调试行为 | 精确控制 |
| 使用插件 | 自动屏蔽或跳过 | 高级用户 |
| 注入脚本 | 定制化绕过逻辑 | Tampermonkey 用户 |
| 火狐浏览器 | 在调试语句上暂停 | all in |
---
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast.js
================================================
const parser = require("@babel/parser");
const template = require("@babel/template").default;
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
const fs = require("fs");
const path = require('path');
// lx.js 是被混淆的js文件
var jscode = fs.readFileSync("lx.js", { encoding: "utf-8"});
const visitor_string = {
'StringLiteral|NumericLiteral'(path) {
delete path.node.extra
}
};
const visitor_number = {
'UnaryExpression'(path) {
const {value} = path.evaluate();
switch (typeof value) {
case 'boolean':
path.replaceWith(t.BooleanLiteral(value))
break;
case 'string':
path.replaceWith(t.StringLiteral(value))
break;
case 'number':
path.replaceWith(t.NumericLiteral(value))
break;
default:
break;
}
}
}
const visitor_function = {
MemberExpression(path) {
let property = path.get('property')
if (property.isStringLiteral()) {
let value = property.node.value;
path.node.computed = false
property.replaceWith(t.Identifier(value))
}
}
};
const visitor_del_cons =
{
VariableDeclarator(path) {
const {id} = path.node;
const binding = path.scope.getBinding(id.name);
if (!binding || binding.constantViolations.length > 0) {
return;
}
if (binding.referencePaths.length === 0) {
path.remove();
}
},
}
const visitor_eval =
{
CallExpression(path)
{
let {callee,arguments} = path.node;
if (!t.isIdentifier(callee,{name:'eval'})) return;
if (arguments.length !== 1 || !t.isStringLiteral(arguments[0])) return;
let value = arguments[0].value;
path.replaceWith(t.Identifier(value));
},
}
// 将JS源码转换成语法树
let ast = parser.parse(jscode);
traverse(ast, visitor_string); //识别字符串
traverse(ast, visitor_number); //计算表达式 !![] -> true
traverse(ast, visitor_function); //将a["length"]转为a.length
traverse(ast, visitor_del_cons); //删除未被调用的变量
traverse(ast, visitor_eval); //处理eval函数
let {code} = generator(ast, {jsescOption: {"minimal": true}});
fs.writeFile('lx_decoded.js', code, (err) => {});
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/readme.md
================================================
补充部分的内容收集于网络,内容并未出现在书籍中,如有侵权请联系作者进行删除。
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/while-if转变为while-switch.js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode =
`
function test() {
var index = 0,
arr = [3, 0, 2, 1],
pindex;
while (1) {
pindex = arr[index++];
if (pindex < 1) {
console.log("this is index 0");
} else if (pindex < 2) {
console.log("this is index 1");
return;
} else if (pindex < 3) {
console.log("this is index 2");
} else {
console.log("Hello world!");
}
}
}
`;
let ast = parse(jscode);
const visitor =
{
"WhileStatement"(path) {
let {test, body} = path.node;
//******************************************************特征判断开始
if (!t.isNumericLiteral(test, {value: 1})) return;
let block_body = body.body;
if (block_body.length !== 2 || !t.isExpressionStatement(block_body[0]) || !t.isIfStatement(block_body[1])) {
return;
}
//******************************************************特征判断结束
let {left, right} = block_body[0].expression;
let name = left.name;
let if_arrs = [];
path.traverse({
"IfStatement"(_path) {
let {test, consequent, alternate} = _path.node;
let {left, operator, right} = test;
if (!t.isIdentifier(left, {name: name}) || operator !== '<' || !t.isNumericLiteral(right)) return;
if (consequent.body.length === 1) {
if_arrs[right.value - 1] = consequent.body[0];
} else {
if_arrs[right.value - 1] = consequent;
}
if (!t.isIfStatement(alternate)) {
if (consequent.body.length === 1) {
if_arrs[right.value] = alternate.body[0];
} else {
if_arrs[right.value] = alternate;
}
}
},
})
if (if_arrs.length === 0) return;
for (var i = 0; i < if_arrs.length - 1; i++) {
consequent = [if_arrs[i], t.BreakStatement()];
if_arrs[i] = t.SwitchCase(test = t.NumericLiteral(i), consequent = consequent);
}
consequent = [if_arrs[if_arrs.length - 1], t.BreakStatement()];
if_arrs[i] = t.SwitchCase(test = null, consequent = consequent);
let new_node = t.SwitchStatement(right, if_arrs);
path.get('body.body.1').replaceInline(new_node);
path.get('body.body.0').remove();
},
}
//some function code
traverse(ast, visitor);
let {code} = generator(ast);
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/三目运算符.js
================================================
/*
desc : 把 a = m?11:22; 转成 m ? a = 11 : a = 22;
*/
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "a = m ? 11 : 22;";
let ast = parse(jscode);
const visitor =
{
ConditionalExpression(path){
let {test, consequent, alternate} = path.node;
const ParentPath = path.parentPath;
if(t.isAssignmentExpression(ParentPath)){
let {operator, left} = ParentPath.node;
if (operator === '='){
consequent = t.AssignmentExpression('=', left, consequent);
alternate = t.AssignmentExpression('=', left, alternate);
ParentPath.replaceWith(t.ConditionalExpression(test, consequent, alternate))
}
}
}
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
/*
1.节点类型变了,由 AssignmentExpression 类型变成了ConditionalExpression 类型。
2.ConditionalExpression 子节点的 consequent 和 alternate 都变成了 AssignmentExpression 类型。
*/
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/函数调用处自动替换计算值.js
================================================
/*
*/
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "function add(a, b) {\n" +
" return a + b;\n" +
"}\n" +
"\n" +
"let c = add(1, 2);";
let ast = parse(jscode);
const visitor =
{
FunctionDeclaration(path) {
let {id} = path.node;
let code = path.toString();
if (code.indexOf("try") !== -1 || code.indexOf("random") !== -1 || code.indexOf("Date") !== -1) {
// 不是纯函数,不处理
return
}
eval(code);
let scope = path.scope;
const binding = path.scope.parent.getBinding(id.name);
if (!binding || binding.constantViolations.length > 0) {
return
}
for (const refer_path of binding.referencePaths) {
// 查找父节点
let call_express = refer_path.findParent(p => p.isCallExpression());
let arguments = call_express.get("arguments");
let args = [];
// 判断参数是否为 Literal 类型
arguments.forEach(arg => {
args.push(arg.isLiteral())
})
// 自行编写判断条件,example
if (args.length === 0 || args.indexOf(false) !== -1) {
continue
}
try {
// 计算值
let value = eval(call_express.toString());
value && call_express.replaceWith(t.valueToNode(value));
} catch (e) {
}
}
}
}
//some function code
traverse(ast, visitor);
let {code} = generator(ast);
console.log(code);
/*
1.函数需要满足在任意位置都能执行。就是一个函数声明的代码,随便拷贝到任意的地方都能直接运行,不会报错。说白了其实也就是函数体内的所有变量或者对象,其作用域只在函数体里面。
2.定义的函数,对于实参是固定的,其结果也是固定的。请大家自行百度 纯函数 的概念
3.实参必须是字面量,因为对于遍历的节点来说。只有是字面量,才能给你计算出具体的字,如果不是字面量,实参对它来说就是 undefined 的,是无法计算的。
4.将函数定义eval到本地环境,然后根据作用域找到函数调用的位置。再eval该表达式即可。注意需要使用try...catch语句,避免错误。
*/
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除多余的空行和空语句.js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "var a = 123;\n" +
"\n" +
";\n" +
"\n" +
"var b = 456;";
let ast = parse(jscode);
const visitor =
{
EmptyStatement(path)
{
path.remove();
},
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除所有的代码注释.js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "var a = 123; //this is single line comment\n" +
"\n" +
"/*\n" +
"\n" +
"This is a multiline comments;\n" +
"\n" +
"test\n" +
"\n" +
"test\n" +
"\n" +
"test\n" +
"\n" +
"*/\n" +
"\n" +
"var b = 456;";
let ast = parse(jscode);
const visitor =
{
//TODO write your code here!
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast, {comments:false});
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除未被使用的变量.js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "var a = 123,b;\n" +
"\n" +
"let c = 4 + 5;\n" +
"\n" +
"d = a + 12;";
let ast = parse(jscode);
const visitor =
{
VariableDeclarator(path) {
const {id} = path.node;
const binding = path.scope.getBinding(id.name);
//如果变量被修改过,则不能进行删除动作。
if (!binding || binding.constantViolations.length > 0) {
return;
}
//长度为0,说明变量没有被使用过。
if (binding.referencePaths.length === 0) {
path.remove();
}
},
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除未被调用的函数.js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "function i()\n" +
"\n" +
"{\n" +
"\n" +
" var i = 123;\n" +
"\n" +
" i += 2;\n" +
"\n" +
" \n" +
"\n" +
" return 123;\n" +
"\n" +
"}";
let ast = parse(jscode);
const visitor =
{
FunctionDeclaration(path) {
// path.scope.dump();
const {id} = path.node;
const binding = path.scope.parent.getBinding(id.name);
if (!binding || binding.constantViolations.length > 0) {
return;
}
if (binding.referencePaths.length === 0) {
path.remove();
}
},
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/去控制流(for-switch).js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode =
`
function test() {
for (var index = 0; index != 5;) {
switch (index) {
case 0:
console.log("This is case-block 0");
index = 3;
continue;
case 1:
console.log("This is case-block 1");
return;
index = 5;
continue;
case 2:
console.log("This is case-block 2");
index = 1;
continue;
case 3:
console.log("This is case-block 3");
index = 4;
continue;
case 4:
console.log("This is case-block 4");
index = 2;
continue;
}
break;
}
}
`;
let ast = parse(jscode);
const visitor =
{
ForStatement(path) {
//遍历for语句
const { init, update, test, body } = path.node;
//特征判断
if (
!t.isVariableDeclaration(init) ||
!t.isBinaryExpression(test) ||
update !== null
)
return;
let declaration = init.declarations[0];
//获取控制循环的变量及其初始值
const init_name = declaration.id.name;
let init_value = declaration.init.value;
let { left, right, operator } = test;
//特征判断
if (
!t.isIdentifier(left, { name: init_name }) ||
operator !== "!=" ||
!t.isNumericLiteral(right)
)
return;
let test_value = right.value;
let switch_body = body.body[0];
//特征判断
if (!t.isSwitchStatement(switch_body)) return;
let { discriminant, cases } = switch_body;
if (!t.isIdentifier(discriminant, { name: init_name })) return;
let ret_body = [];
let end_flag = false;
//不断的拿到控制循环的变量值
while (init_value !== test_value) {
//如果没有与之匹配的值,直接跳出循环
if (end_flag === true) {
//如果遇到return语句,直接跳出循环
break;
}
for (const each_case of cases) {
let { test, consequent } = each_case;
if (init_value !== test.value) {
continue;
}
if (t.isContinueStatement(consequent[consequent.length - 1])) {
//如果是continue语句,直接删除
consequent.pop();
}
if (t.isExpressionStatement(consequent[consequent.length - 1])) {
//如果是表达式语句,则判断是否包含控制循环的变量的赋值语句
let { expression } = consequent[consequent.length - 1];
if (t.isAssignmentExpression(expression)) {
let { left, right, operator } = expression;
if (t.isIdentifier(left, { name: init_name })) {
//更新控制循环的变量值,并进行删除
init_value = right.value;
consequent.pop();
}
}
}
if (t.isReturnStatement(consequent[consequent.length - 1])) {
end_flag = true;
}
ret_body = ret_body.concat(consequent);
break;
}
}
path.replaceInline(ret_body);
}
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/去控制流(while-switch).js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode =
`
var arr = "3|0|1|2|4".split("|");
var cnt = 0;
while (true) {
switch (arr[cnt++]) {
case "1":
console.log("This is case-block 1");
continue;
case "0":
console.log("This is case-block 0");
continue;
case "2":
console.log("This is case-block 2");
continue;
case "4":
console.log("This is case-block 4");
continue;
case "3":
console.log("This is case-block 3");
continue;
}
break;
}
`;
let ast = parse(jscode);
const visitor =
{
WhileStatement(path) {
const { test, body } = path.node;
//特征语句判断,视情况而定,也可以不判断
if (!t.isBooleanLiteral(test) || test.value !== true) return;
//特征语句判断,body.body[0] 必须是 SwitchStatement 节点,
//注意一定要先判断长度,避免index出错
if (body.body.length === 0 || !t.isSwitchStatement(body.body[0])) return;
let switch_state = body.body[0];
//获取discriminant及cases节点
let { discriminant, cases } = switch_state;
//特征语句判断,经过此判断后,基本可以确定是需要还原的while节点了。
//如果出错了,可以继续增加判断,直到不出错即可
if (!t.isMemberExpression(discriminant) || !t.isUpdateExpression(discriminant.property)) return;
//获取数组名,用于查找该数组。
let arr_name = discriminant.object.name;
let arr = [];
//在这里再加一个特征语句的判断:WhileStatement 节点前面有两个节点
let all_pre_siblings = path.getAllPrevSiblings();
if (all_pre_siblings.length !== 2) return;
all_pre_siblings.forEach((pre_path) => {
//虽然知道是第0个节点,但这里还是做下判断取arr
const { declarations } = pre_path.node;
let { id, init } = declarations[0];
if (arr_name === id.name) {
//如果是定义arr的节点,拿到该arr的值
arr = init.callee.object.value.split("|");
}
//没啥用的语句可以直接删除
pre_path.remove();
});
//新建一个数组变量,用于存放 case 节点
let ret_body = [];
arr.forEach((index) => {
//遍历数组,去case节点
let case_body = [];
for (const tmp of cases){
if(index === tmp.test.value){
case_body = tmp.consequent;
break;
}
}
if (t.isContinueStatement(case_body[case_body.length - 1])) {
//删除 continue语句
case_body.pop();
}
//存放于数组变量中
ret_body = ret_body.concat(case_body);
});
//替换
path.replaceInline(ret_body);
}
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
/*
去控制流(while-switch), 代码不通用,存在优化空间,
比如将 case 做个键值对映射,这样直接取结果就比循环判断好一些
*/
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/合并定义在object对象外面的key、value.js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode =
`
var h = {};
h["aaa"] = "hello wolrd";
h["bbb"] = function (a,b)
{
return a | b;
}
`;
let ast = parse(jscode);
const visitor =
{
VariableDeclarator(path)
{
const {id,init} = path.node;
if (!t.isObjectExpression(init)) return;
let name = id.name;
let properties = init.properties;
let all_next_siblings = path.parentPath.getAllNextSiblings();
for (let next_sibling of all_next_siblings)
{
if (!next_sibling.isExpressionStatement()) break;
let expression = next_sibling.get('expression');
if (!expression.isAssignmentExpression()) break;
let {operator,left,right} = expression.node;
if (operator !== '=' || !t.isMemberExpression(left) || !t.isIdentifier(left.object,{name:name}))
{
break;
}
properties.push(t.ObjectProperty(left.property,right));
next_sibling.remove();
}
},
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
/*
1.object对象使用var定义的,因此遍历 VariableDeclarator 节点即可
2.依次判断后续节点,是否为定义在外面的key和value
3.收集key和value,用于构造ObjectProperty 节点
4. properties 属性是Array对象,只用push方法来增加节点
5.处理完成后删除后续节点。
*/
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理eval函数.js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "eval('var a = 123;');";
let ast = parse(jscode);
const visitor =
{
CallExpression(path)
{
let {callee,arguments} = path.node;
if (!t.isIdentifier(callee,{name:'eval'})) return;
if (arguments.length !== 1 || !t.isStringLiteral(arguments[0])) return;
let value = arguments[0].value;
path.replaceWith(t.Identifier(value));
},
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理条件已知的if语句.js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
// let jscode = "if (true)\n" +
// "{\n" +
// " //do something;\n" +
// " funcA();\n" +
// "}\n" +
// "else\n" +
// "{\n" +
// " //do something;\n" +
// " funcB();\n" +
// "}";
let jscode = "if ('123'==='123')\n" +
" a = 123;\n" +
"else\n" +
" a = 456;";
let ast = parse(jscode);
const visitor1 =
{
BinaryExpression(path) {
let {confident, value} = path.evaluate();
// console.log(path.type, confident, value)
if (confident) {
// console.log(path.node);
path.replaceInline(t.valueToNode(value))
}
}
}
const visitor2 =
{
IfStatement(path) {
let {test, consequent, alternate} = path.node;
if (!t.isBlockStatement(consequent)) {//添加中括号
path.node.consequent = t.BlockStatement([consequent]);
}
if (alternate !== null && !t.isBlockStatement(alternate)) {//添加中括号
path.node.alternate = t.BlockStatement([alternate]);
}
//特征判断,if语句里面的test是否为字面量
if (!t.isLiteral(test)) return;
let value = test.value;
consequent = path.node.consequent;
alternate = path.node.alternate;
if (value) {//替换
path.replaceInline(consequent.body);
} else {//替换
alternate === null ? path.remove() : path.replaceInline(alternate.body);
}
},
}
//some function code
traverse(ast, visitor1);
traverse(ast, visitor2);
let {code} = generator(ast);
console.log(code);
/*
if (true)
//do something;
else
//do something;
与
if (true)
{
//do something;
}
else
{
//do something;
}
解析出来的结构会有小小的差异,不利于处理,因此先将上面的代码转变为下面的代码,再进行处理即可
1.先将if语句块中没有 中括号的处理成 包含中括号的
2.判断if条件里面的值,获取应该执行的语句块
3.用语句块替换整个if表达式即可。
*/
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理条件已知的三元表达式.js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "a = 5 ? 11 : 22;\n" +
"b = 0 ? 33 : 44;";
let ast = parse(jscode);
const visitor =
{
ConditionalExpression(path) {
let { test, consequent, alternate } = path.node;
if (!t.isLiteral(test)) return;
if (test.value) {
path.replaceInline(consequent);
} else {
path.replaceInline(alternate);
}
}
}
//some function code
traverse(ast, visitor);
let {code} = generator(ast);
console.log(code);
// 和常见表达式的计算类似
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理没有实参的自执行函数.js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "!function () {\n" +
" a = 123;\n" +
"}();";
let ast = parse(jscode);
const visitor = {
UnaryExpression(path) {
const {operator, argument} = path.node;
if (operator !== "!" || !t.isCallExpression(argument)) return;
let {callee, arguments} = argument;
if (!t.isFunctionExpression(callee) || arguments.length !== 0) return;
path.replaceInline(callee.body.body);
},
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/对同一节点使用多个方法.js
================================================
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "";
let ast = parse(jscode);
const visitor =
{
CallExpression:
{// 注意顺序
enter: [reduce_call_express, delete_empty_params]
},
}
//some function code
function reduce_call_express(path) {
}
function delete_empty_params(path) {
}
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
/*
假设想对一个函数表达式的 CallExpression 节点进行进行实参还原,
如果还原后,没有了实参和形参,假如又可以将函数体里面的代码提取出来。
这个时候就需要两个方法来分别进行处理了
reduce_call_express 还原函数的实参
delete_empty_params 将参数为空的函数进行处理,将函数体里面的代码直接提取出来
*/
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/条件表达式拆分为if语句.js
================================================
/*
*/
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode =
`
r ? r > 1 ? e.apply(t, arguments) : e.call(t, n) : e.call(t);
`;
let ast = parse(jscode);
const visitor =
{
ConditionalExpression(path) {
let { test, consequent, alternate } = path.node;
const ParentPath = path.parentPath;
if (t.isExpressionStatement(ParentPath)) {
if (!t.isExpressionStatement(consequent)) {
consequent = t.BlockStatement([t.ExpressionStatement(consequent)]);
}
if (!t.isExpressionStatement(alternate)) {
alternate = t.BlockStatement([t.ExpressionStatement(alternate)]);
}
ParentPath.replaceInline(t.IfStatement(test, consequent, alternate));
}
}
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
/*
r ? r > 1 ? e.apply(t, arguments) : e.call(t, n) : e.call(t);
if (r) {
if (r > 1) {
e.apply(t, arguments);
} else {
e.call(t, n);
}
} else {
e.call(t);
}
*/
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/构造节点.js
================================================
/*
* 将 var a; 转换为 var a = 123 + 456;
*
* */
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "var a";
let ast = parse(jscode);
const visitor =
{
// 方法一
VariableDeclarator(path){
const {init} = path.node;
let node = {
type: "BinaryExpression",
operator: "+",
left: {
type: "NumericLiteral",
value: 123,
},
right: {
type: "NumericLiteral",
value: 456,
}
}
init || path.set("init", node)
},
// 方法二
/* VariableDeclarator(path){
const {init} = path.node;
init || path.set("init", t.binaryExpression('+',t.valueToNode(123),t.valueToNode(456)))
},*/
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/节点类型转换.js
================================================
/*
desc : 将 BinaryExpression 类型转换为 CallExpression 类型
*/
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "var a = 123 | 456;";
let ast = parse(jscode);
const visitor =
{
"VariableDeclarator"(path)
{
const init_path = path.get('init');
if (!init_path.isBinaryExpression()) return
init_path.node.type = "CallExpression";
let {operator,left,right} = init_path.node;
init_path.node.arguments = [left,right];
let id = null;
let frist_arg = t.Identifier('s');
let second_arg = t.Identifier('h');
let params = [frist_arg,second_arg];
let args = t.BinaryExpression(operator,frist_arg,second_arg);
let return_state = t.ReturnStatement(args);
let body = t.BlockStatement([return_state]);
init_path.node.callee = t.FunctionExpression(id ,params,body);
},
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原Array对象.js
================================================
/*
*/
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "var _2$SS = function (_SSz, _1111) {\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" +
" var _2Szs = _l1L1[5] + _l1L1[7] + (_l1L1[4] + _l1L1[2]),\n" +
" _I1il1 = _l1L1[9] + (_l1L1[10] + _l1L1[11]);\n" +
"\n" +
" var _0ooQoO = _l1L1[0];\n" +
" var _$Z22 = _l1L1[12],\n" +
" _2sS2 = _l1L1[8];\n" +
" return _l1L1[6] + _l1L1[3] + _l1L1[1];\n" +
"};";
let ast = parse(jscode);
const visitor =
{
VariableDeclarator(path){
// 还原数组对象
const {id, init} = path.node;
// 非Array或者没有元素, 返回
if (!t.isArrayExpression(init) || init.elements.length===0) return;
let elements = init.elements;
// 获取binding实例
const binding = path.scope.getBinding(id.name);
for ( const ref_path of binding.referencePaths){
// 获取 MemberExpression 父节点
let member_path = ref_path.findParent(p=>p.isMemberExpression());
let property = member_path.get('property');
// 索引值不是 NumericLiteral 类型的不处理
if(!property.isNumericLiteral()){
continue;
}
// 获取索引值
let index = property.node.value;
// 获取索引值对应的节点, 并替换
let arr_ele = elements[index];
member_path.replaceWith(arr_ele)
}
}
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原object对象.js
================================================
/*
date : 2020/8/11
desc :
*/
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "var a = {\n" +
" \"YJJox\": \"object\",\n" +
" \"sbTga\": function (b, c) {\n" +
" return b | c;\n" +
" },\n" +
" \"iwvEK\": function (b, c) {\n" +
" return b << c;\n" +
" },\n" +
" \"HqkiD\": function (b, c) {\n" +
" return b(c);\n" +
" }\n" +
"};\n" +
"b = a[\"iwvEK\"](1, 3), c = a[\"sbTga\"](111, 222), d = a[\"YJJox\"], e = a[\"HqkiD\"](String.fromCharCode, 49);";
let ast = parse(jscode);
const visitor =
{
VariableDeclarator(path) {
const {id, init} = path.node;
//特征判断,对象为空则不处理
if (!t.isObjectExpression(init) || init.properties.length === 0) return;
let name = id.name;
let scope = path.scope;
for (const property of init.properties) {//遍历key、value
let key = property.key.value;
let value = property.value;
//一般ob混淆,key长度都是5,也有是3的,自行调整即可。
if (key.length !== 5) return;
//如果是字面量
if (t.isLiteral(value)) {
scope.traverse(scope.block, {
//遍历MemberExpression,找出与key相同的表达式
MemberExpression(_path) {
let _node = _path.node;
if (!t.isIdentifier(_node.object, {name: name})) return;
if (!t.isLiteral(_node.property, {value: key})) return;
_path.replaceWith(value);
},
})
}
//如果是函数表达式
else if (t.isFunctionExpression(value)) {
let ret_state = value.body.body[0];
//特征判断,如果不是return表达式
if (!t.isReturnStatement(ret_state)) continue;
scope.traverse(scope.block, {
CallExpression: function (_path) {
//遍历CallExpression
let {callee, arguments} = _path.node;
if (!t.isMemberExpression(callee)) return;
if (!t.isIdentifier(callee.object, {name: name})) return;
if (!t.isLiteral(callee.property, {value: key})) return;
if (t.isCallExpression(ret_state.argument) && arguments.length > 0) {
//构造节点
_path.replaceWith(t.CallExpression(arguments[0], arguments.slice(1)));
} else if (t.isBinaryExpression(ret_state.argument) && arguments.length === 2) {
//构造节点
let replace_node = t.BinaryExpression(ret_state.argument.operator, arguments[0], arguments[1]);
_path.replaceWith(replace_node);
} else if (t.isLogicalExpression(ret_state.argument) && arguments.length === 2) {
//构造节点
let replace_node = t.LogicalExpression(ret_state.argument.operator, arguments[0], arguments[1]);
_path.replaceWith(replace_node);
}
}
})
}
}
},
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
/*
1.这里是 VariableDeclarator 节点,子节点 init 是 ObjectExpression 类型的表达式,因此我们可以遍历VariableDeclarator节点,便于获取 对象名 及整个对象
2.遍历 ObjectExpression 节点的 properties 属性,它是一个 数组,遍历这个数组,获取key和value
3.判断 value 的节点类型,如果是字面量,则可以直接进行替换;如果是函数表达式,则需要通过返回的表达式类型构造相应的表达式。然后在作用域块内遍历 MemberExpression (PS:a["sbTga"]) 节点,如果是对象名,并且当前的key值也相等,则进行节点替换。
4.遍历 properties 完毕后,可以试着删除整个 VariableDeclarator 节点,如果不报错就没事。
*/
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原定义的字面量.js
================================================
/*
date : 2020/8/11
desc :
*/
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "var s = 92;\n" +
"b = Z(1324801, 92);";
let ast = parse(jscode);
const visitor =
{
"Identifier"(path)
{
const {confident,value} = path.evaluate();
confident && path.replaceInline(t.valueToNode(value));
},
// 替换完了就没用了,将其删除
VariableDeclarator(path)
{
const {id,init} = path.node;
if (!t.isLiteral(init)) return;//只处理字面量
const binding = path.scope.getBinding(id.name);
if (!binding || binding.constantViolations.length > 0)
{//如果该变量的值被修改则不能处理
return;
}
for (const refer_path of binding.referencePaths)
{
refer_path.replaceWith(init);
}
path.remove();
},
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原成中文字符.js
================================================
/*
*/
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "var s = \"\u4f60\u597d\uff0c\u4e16\u754c;\"\n" +
"var a = \"\u0068\u0065\u006c\u006c\u006f\u002c\u0020\u0077\u006f\u0072\u0064\";";
let ast = parse(jscode);
const visitor =
{
StringLiteral(path)
{
path.get('extra').remove();
},
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast, {jsescOption:{"minimal":true}});
console.log(code);
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原自执行函数的实参.js
================================================
/*
*/
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const t = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode = "!function (a, b) {\n" +
" c = a | b;\n" +
"}(111, 222);";
let ast = parse(jscode);
const visitor =
{
CallExpression(path){
let callee = path.get('callee');
let arguments = path.get('arguments');
if(!t.isFunctionExpression(callee) || arguments.length ===0){
// 实参的长度判断可以写死
return;
}
// 获取形参
let params = callee.get('params');
let scope = callee.scope;
for ( let i =0; i< arguments.length; i++){
// 遍历实参, 因为形参可能比实参长
let arg = params[i];
let {name} = arg.node;
const binding = scope.getBinding(name);
if(!binding || binding.constantViolations.length > 0){
// 形参发生改变,不能被还原
continue;
}
for(refer_path of binding.referencePaths){
// 字面量可以直接替换
refer_path.replaceWith(arguments[i]);
}
arg.remove();
arguments[i].remove();
}
}
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
// 替换完之后可以通过无参的自执行插件再替换
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/逗号表达式.js
================================================
/*
*/
const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const types = require("@babel/types");
const generator = require("@babel/generator").default;
let jscode =
`
b = (0,g.o)(a);
c = (a=1,b=2,c=3,d=4,e=5,f);
function get()
{
return a=1,b=2,a +=2,a;
}
`;
let ast = parse(jscode);
const visitor =
{
SequenceExpression: {
exit(path){
let expressions = path.get('expressions');
let last_expression = expressions.pop();
let statement = path.getStatementParent();
if(statement){
for(let expression of expressions)
{
// 删除无用的干扰代码
if(expression.isLiteral() ||expression.isIdentifier())
{
expression.remove();
continue;
}
statement.insertBefore(types.ExpressionStatement(expression=expression.node));
}
path.replaceInline(last_expression);
}
}
}
}
//some function code
traverse(ast,visitor);
let {code} = generator(ast);
console.log(code);
/*******************************************
b = (0,g.o)(a);
c = (a=1,b=2,c=3,d=4,e=5,f);
function get()
{
return a=1,b=2,a +=2,a;
}
===>
b = g.o(a);
a = 1;
b = 2;
c = 3;
d = 4;
e = 5;
c = f;
function get() {
a = 1;
b = 2;
a += 2;
return a;
}
******************************************/
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/for_swith.js
================================================
const visitor =
{
ForStatement(path) {
const { init, update, test, body } = path.node;
if (
!t.isVariableDeclaration(init) ||
!t.isBinaryExpression(test) ||
update !== null
)
return;
let declaration = init.declarations[0];
const init_name = declaration.id.name;
let init_value = declaration.init.value;
let { left, right, operator } = test;
//判断特征
if (
!t.isIdentifier(left, { name: init_name }) ||
operator !== "!=" ||
!t.isNumericLiteral(right)
)
return;
let test_value = right.value;
let switch_body = body.body[0];
//判断特征
if (!t.isSwitchStatement(switch_body)) return;
let { discriminant, cases } = switch_body;
if (!t.isIdentifier(discriminant, { name: init_name })) return;
let ret_body = [];
let end_flag = false;
while (init_value !== test_value) {
if (end_flag === true) {
break;
}
for (const each_case of cases) {
let { test, consequent } = each_case;
if (init_value !== test.value) {
continue;
}
if (t.isContinueStatement(consequent[consequent.length - 1])) {
consequent.pop();
}
if (t.isExpressionStatement(consequent[consequent.length - 1])) {
let { expression } = consequent[consequent.length - 1];
if (t.isAssignmentExpression(expression)) {
let { left, right, operator } = expression;
if (t.isIdentifier(left, { name: init_name })) {
init_value = right.value;
consequent.pop();
}
}
}
if (t.isReturnStatement(consequent[consequent.length - 1])) {
end_flag = true;
}
ret_body = ret_body.concat(consequent);
break;
}
}
path.replaceInline(ret_body);
}
}
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/lx.js
================================================
function test() {
for (var index = 0; index != 5;) {
switch (index) {
case 0:
console.log("This is case-block 0");
index = 3;
continue;
case 1:
console.log("This is case-block 1");
return;
index = 5;
continue;
case 2:
console.log("This is case-block 2");
index = 1;
continue;
case 3:
console.log("This is case-block 3");
index = 4;
continue;
case 4:
console.log("This is case-block 4");
index = 2;
continue;
}
break;
}
}
================================================
FILE: 第三章:Web Js逆向/3.13 反混淆AST/readme.md
================================================
可能大家对ast不太理解,其实是通过生成语法树(AST),可快速修改代码中的一些混淆处理,从而简化代码,便于后续分析。
比如通过Python来把JS转为AST并进行简单的操作,内容很简单。
比如我们下图中的JS代码,有sum和minus两个函数,一个变量a,两个换行\n,以及一次sum函数的调用,参数为1和2。

通过pyjsparser库将script代码转换成为json-ast格式。
pyjsparser是目前用于 python 的最快和最易理解的 JavaScript 解析器。可将JavaScript翻译成Python,即在Python中运行JavaScript代码。
import pyjsparser
js_ast = pyjsparser.parse(script)
转换后用Json格式化工具打开。

在body下的元素有这几种类型:
函数声明:FunctionDeclaration
空语句(\n):EmptyStatement
变量声明:VariableDeclaration
表达式语句:ExpressionStatement
根据Json可看到FunctionDeclaration中有基本的函数名、参数名、参数类型、块语句和返回语句等。
此外,表达式语句中还有调用表达式(CallExpression)、二元表达式(BinaryExpression)、赋值表达式(AssignmentExpression)等等。
那么我们就可以通过这些Type,以修改Json对象的方式去操作这棵语法树。比如根据是否被调用去删除一些无用的对象,删除未调用的函数,或根据规则去替换一些结构,修改一些节点。

假如这是一段时间长并且难以阅读的代码,我们需要先将其转为AST,然后遍历所有函数,来查找未被调用的方法,然后进行删除,再根据AST转回正常的JS代码。
```python
# 完整代码如下,大家自己试试删除无用变量a吧!
# js2py依赖于pyjsparser,所以安装js2py即可安装pyjsparser
# pip install js2py
script = '''
function sum(a,b){
c = minus(2,3)
return a+c;
};
function minus(a2,b2){
return a2-b2;
};
function dddd(a2,b2){
return a2-b2;
};
var a = 123;
sum(1,2)
'''
import pyjsparser
js_ast = pyjsparser.parse(script)
# 获取所有方法
funcList = []
for i in js_ast['body']:
if i['type'] =='FunctionDeclaration':
name = i['id']['name']
funcList.append(name)
# 查找未被调用的方法
noCallList = []
for func in funcList:
searchStatement = "{'type': 'CallExpression', 'callee': {'type': 'Identifier', 'name': '%s'}"%func
if searchStatement not in str(js_ast):
noCallList.append(func)
# 删除未调用的方法
for i in js_ast['body']:
if i['type'] =='FunctionDeclaration':
if i['id']['name'] in noCallList:
js_ast['body'].remove(i)
#js_ast['body'][0]['id']['name'] = 'pythonlx' # 修改一个函数名
# 用AST重新生成js代码
import js2py.py_node_modules.escodegen as escodegen
escodegen = escodegen.var.get('escodegen')
res = escodegen.get('generate')(js_ast)
print(res.to_python()
```
执行后,可以发现未被调用的dddd方法已经被删除。
代码很简单,大家试试如何删除无关变量a吧!
本文牛刀小试,更多内容我们后续再见!

================================================
FILE: 第三章:Web Js逆向/3.3 加密参数定位方法/3.3.7 注入和Hook/readme.md
================================================
参数定位工具的下载地址在代码库中。
下载地址:https://pan.baidu.com/s/1OmMiE4rJrTNwarw3EJbz0A?pwd=thyl
---
下面是一些常用的Js Hook代码。
## Hook setInterval
```js
let _setInterval=setInterval;
setInterval=function(a,b){
if(a.toString().indexOf("debugger")!=-1){
return null;
}
_setInterval(a,b);
}
```
## Hook header
```js
var header_old = window.XMLHttpRequest.prototype.setRequestHeader;
window.XMLHttpRequest.prototype.setRequestHeader = function (key, value) {
if (key=='k'){
console.log(key, value)
debugger;
}
if (key=='token'){
console.log(key, value)
debugger;
}
return header_old.apply(this, arguments);
}
```
## Hook Cookie Info
```javascript
var cookie_cache = document.cookie;
Object.defineProperty(document, 'cookie', {
get: function() {
console.log('Getting cookie');
return cookie_cache;
},
set: function(val) {
console.log('Setting cookie', val);
var cookie = val.split(";")[0];
var ncookie = cookie.split("=");
var flag = false;
var cache = cookie_cache.split("; ");
cache = cache.map(function(a){
if (a.split("=")[0] === ncookie[0]){
flag = true;
return cookie;
}
return a;
})
cookie_cache = cache.join("; ");
if (!flag){
cookie_cache += cookie + "; ";
}
this._value = val;
return cookie_cache;
},
});
```
## Hook Json Info
```javascript
var my_stringify = JSON.stringify;
JSON.stringify = function (params){
console.log("json_stringify:", params);
return json_stringify(params);
};
var my_parse = JSON.parse;
JSON.parse = function (params){
console.log("json_parse:", params);
return json_parse(params);
};
```
## Hook WebSocket Info
```javascript
WebSocket.prototype.senda = WebSocket.prototype.send;
WebSocket.prototype.send = function (data){
console.info("Hook WebSocket", data);
return this.senda(data)
}
```
## Hook Cookie
```js
(function() {
'use strict';
var cookie_cache = document.cookie;
Object.defineProperty(document, 'cookie', {
get: function() {
// console.log(cookie_cache);
return cookie_cache;
},
set: function(val) {
if (val.indexOf('gdxidpyhxdE') != -1){
console.log('cookie',val)
debugger;
}
var cookie = val.split(";")[0];
var ncookie = cookie.split("=");
var flag = false;
var cache = cookie_cache.split(";");
cache = cache.map(function(a){
if (a.split("=")[0] === ncookie[0]){
flag = true;
return cookie;
}
return a;
})
cookie_cache = cache.join(";");
if (!flag){
cookie_cache += cookie + ";";
}
},
});
})();
```
## Hook XHR
```javascript
// 代码作者:掘金tager
// xhr中的方法拦截,eg: open、send etc.
function hookFunction(funcName, config) {
return function () {
var args = Array.prototype.slice.call(arguments)
// 将open参数存入xhr, 在其它事件回调中可以获取到。
if (funcName === 'open') {
this.xhr.open_args = args
}
if (config[funcName]) {
console.log(this, 'this')
// 配置的函数执行结果返回为true时终止调用
var result = config[funcName].call(this, args, this.xhr)
if (result) return result;
}
return this.xhr[funcName].apply(this.xhr, arguments);
}
}
// xhr中的属性和事件的拦截
function getterFactory(attr, config) {
return function () {
var value = this.hasOwnProperty(attr + "_") ? this[attr + "_"] : this.xhr[attr];
var getterHook = (config[attr] || {})["getter"]
return getterHook && getterHook(value, this) || value
}
}
// 在赋值时触发该工厂函数(如onload等事件)
function setterFactory(attr, config) {
return function (value) {
var _this = this;
var xhr = this.xhr;
var hook = config[attr]; // 方法或对象
this[attr + "_"] = value;
if (/^on/.test(attr)) {
// note:间接的在真实的xhr上给事件绑定函数
xhr[attr] = function (e) {
// e = configEvent(e, _this)
var result = hook && config[attr].call(_this, xhr, e)
result || value.call(_this, e);
}
} else {
var attrSetterHook = (hook || {})["setter"]
value = attrSetterHook && attrSetterHook(value, _this) || value
try {
// 并非xhr的所有属性都是可写的
xhr[attr] = value;
} catch (e) {
console.warn('xhr的' + attr + '属性不可写')
}
}
}
}
// 核心拦截的handler
function xhrHook(config) {
// 存储真实的xhr构造器, 在取消hook时,可恢复
window.realXhr = window.realXhr || XMLHttpRequest
// 重写XMLHttpRequest构造函数
XMLHttpRequest = function () {
var xhr = new window.realXhr()
// 真实的xhr实例存储到自定义的xhr属性中
this.xhr = xhr
// note: 遍历实例及其原型上的属性(实例和原型链上有相同属性时,取实例属性)
for (var attr in xhr) {
if (Object.prototype.toString.call(xhr[attr]) === '[object Function]') {
this[attr] = hookFunction(attr, config); // 接管xhr function
} else {
// attention: 如果重写XMLHttpRequest,必须要全部重写,否则在ajax中不会触发success、error(原因是3.x版本是在load事件中执行success)
Object.defineProperty(this, attr, { // 接管xhr attr、event
get: getterFactory(attr, config),
set: setterFactory(attr, config),
enumerable: true
})
}
}
}
return window.realXhr
}
// 解除xhr拦截,归还xhr管理权
function unXhrHook() {
if (window[realXhr]) XMLHttpRequest = window[realXhr];
window[realXhr] = undefined;
}
// 执行部分
xhrHook({
open: function (args, xhr) {
console.log("open called!", args, xhr)
// return true // 返回true将终止请求,这个就是常规拦截的精髓了
},
setRequestHeader: function (args, xhr) {
console.log("setRequestHeader called!", args, xhr)
},
onload: function (xhr) {
// 对响应结果做处理
this.responseText += ' tager'
}
})
```
================================================
FILE: 第三章:Web Js逆向/3.3 加密参数定位方法/readme.md
================================================
目前主流的定位方法如下
## 全局搜索
适用于:参数名是固定字符串(如`sign`、`token`、`timestamp`、`nonce`),且未被混淆的场景。
**操作步骤**:
1. 打开浏览器开发者工具(F12)→ 切换到`Sources`面板 → 点击左侧搜索图标(Ctrl+Shift+F);
2. 输入目标参数名(如`sign`),选择 “Search in all files”;
3. 分析搜索结果:
* 优先看`=` 、`:` 、`push`、`append`等赋值 / 拼接逻辑(如`data.sign = xxx`、`params['sign'] = xxx`);
* 排除纯注释、日志打印、无关引用的结果;
4. 实战技巧:
* 若参数名被混淆(如`s`、`_0x123`),可先搜索参数值的特征(比如参数值是 32 位 md5,可搜`md5`、`hash`、`hex`);
* 搜索时加通配符,如`sign*=`、`*sign:`,缩小范围。
* 加解密可以搜 encrypt、decrypt等关键字。
## XHR追踪
仅适用于:参数出现在 AJAX 请求(XHR/Fetch)中,想知道请求发送前参数是怎么组装的。
## 堆栈调试
适用于:参数由函数调用生成(如sign = generateSign()),想找到generateSign的定义。
## Hook拦截
见hook脚本
## DOM断点
在特定场景下极其好用的方法 —— 尤其当参数生成和**DOM 操作(点击、输入、元素变化)**强相关时,Elements 断点能精准捕捉到触发参数生成的交互逻辑。
### 适用场景
Elements 断点不是通用型方法,但在以下场景中能解决其他方法搞不定的问题:
* 参数由 DOM 交互触发生成(比如点击 “登录” 按钮、输入验证码后生成`sign`参数);
* 参数生成逻辑绑定在 DOM 事件上(如`onclick`、`onchange`、`onsubmit`);
* 页面通过动态修改 DOM(如添加 / 删除节点、修改属性)触发参数组装;
* 想找到 “点击按钮后→参数生成→发送请求” 的完整链路。
### 断点类型
**Break on subtree modifications:** 目标元素的子节点被添加 / 删除 / 修改时触发
**Break on attribute modifications:** 目标元素的属性(如`value`、`data-sign`、`class`)被修改时触发
**Break on node removal:** 目标元素被从 DOM 树中移除时触发
### 避坑点
1. **避免过度使用**:仅在参数和 DOM 交互相关时使用,否则会触发大量无关断点(比如页面频繁渲染 DOM);
2. **区分事件类型**:点击按钮优先看`click`事件,输入内容优先看`input`/`change`事件;
3. **处理异步逻辑**:若参数在事件回调的异步函数中生成(如`setTimeout`、`Promise`),断住后需在调用栈中找异步回调的入口;
4. **注意影子 DOM**:部分页面使用 Shadow DOM(如 Vue/React 的组件),需在 Elements 面板开启 “Show user agent shadow DOM”(设置→Preferences→Elements),才能看到完整 DOM 结构。
## 进阶技巧
技巧 1:结合 Event Listeners 面板
断住后,在 Elements 面板右侧找到`Event Listeners`(事件监听器):
* 筛选目标元素绑定的事件(如`click`、`change`);
* 点击事件后的 “↗” 箭头,直接跳转到事件处理函数的定义位置,快速定位参数生成逻辑。
技巧 2:处理动态绑定的事件
若事件是通过`addEventListener`动态绑定(而非`onclick`属性):
1. 添加 Elements 断点断住后;
2. 在调用栈中找`dispatchEvent`、`addEventListener`相关的函数;
3. 向上回溯,找到事件回调函数,即为参数生成的入口。
技巧 3:配合条件过滤
若 DOM 频繁变化导致断点触发过多:
1. 右键断点→`Edit condition`;
2. 输入条件(如`attrName === 'data-sign'`),仅当修改`data-sign`属性时才断住,减少无效断点。
## 内存定位
### 内存漫游助手 ast-hook-for-js-RE
聚焦「执行前 AST 语法树」: https://github.com/JSREI/ast-hook-for-js-RE
ast-hook-for-js-RE(AST 钩子工具)是基于抽象语法树(AST)拦截 的 JS 逆向工具,核心逻辑是:在 JS 代码被 V8 引擎编译执行前,先解析成 AST 语法树,通过修改 / 挂钩 AST 节点(如函数调用、变量赋值、加密 API 调用),实现对加密逻辑的拦截、篡改或还原。
它的核心依赖是 `esprima`(AST 解析)、`estraverse`(AST 遍历)、`escodegen`(AST 还原代码),以及 `frida`(跨平台挂钩),是 JS 逆向中「静态 + 动态结合」的典型工具。
**关键特点**:
* 「前置拦截」:代码还没执行,就先修改语法树,比如把`CryptoJS.encrypt`替换成自定义函数,执行时直接拿到明文参数;
* 「后置读取」:代码已经执行,内存中已有完整的执行上下文,只能读取数据,无法修改已执行的逻辑;
* 「数据提取」:核心目标是拿到运行时的真实数据(比如混淆代码执行后内存中的密钥),而非修改逻辑;
### 推理算法助手 help\_tool
[https://gitcode.com/gh\_mirrors/he/help\_tool](https://gitcode.com/gh_mirrors/he/help_tool)
一款专为加密分析设计的工具,能够帮助用户快速识别和推测出使用的加密算法类型,并尝试解密出明文。
推理算法助手(help\_tool)的核心实现原理围绕**加密算法特征识别、进程内存分析、模型辅助推理**三大核心逻辑展开,结合逆向工程实战场景需求,实现加密算法自动识别与明文还原。
工具内置了主流加密算法(哈希、对称加密、非对称加密)的**特征规则库**,通过分析输入密文的格式、长度、编码特征,初步筛选候选算法。通过**预训练的特征模型**捕捉加密算法的深层特征(而非仅依赖规则),尤其适用于密文格式不标准、部分参数未知(如密钥、IV)的场景。

### 通俗化理解(友好版)
1. **推理算法助手**:像「密码破译专家」—— 你给它密文,它通过特征库匹配、扒进程内存,告诉你 “这是 AES 加密,明文是 XXX”,核心是「从密文倒推算法和明文」,不干涉代码执行,只看最终结果。
2. **ast-hook-for-js-RE**:像「代码执行前的安检员」——JS 代码还没跑起来,先把代码拆成 AST 语法树,你可以挂钩加密函数、篡改参数,甚至让加密逻辑失效,核心是「主动控制代码怎么执行」。
================================================
FILE: 第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/readme.md
================================================
新增webpack逆向的案例
案例地址:https://space.bilibili.com/390499740
可以用于webpack解包,代码格式化、反混淆的在线站点
https://webcrack.netlify.app/
================================================
FILE: 第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/webpack-export.js
================================================
var lx;
!function (e){
var report = {};
function o(n){
if (report[n])
return report[n].exports;
var t = report[n] = {
i:n,
l:!1,
exports:{}
};
return e[n].call(t.exports,t,t.exports,o),
t.l = !0,
t.exports
}
lx = o;
}({
// 添加webpack模块
// "method":function(e){}
});
// 调用模块函数
// var t = lx("method");
================================================
FILE: 第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例一.js
================================================
// 贝壳网登录的webpack逆向案例
window = {}
window.location = {
href:'https://zz.ke.com/?utm_source=baidu&utm_medium=pinzhuan&utm_term=biaoti&utm_content=biaotimiaoshu&utm_campaign=wyzhengzhou'
}
document = {
}
var aaa;
var ddd;
navigator = {
appName:"Netscape"
}
!function(n) {
var r = {};
function i(t) {
if (r[t])
return r[t].exports;
var e = r[t] = {
i: t,
l: !1,
exports: {}
};
return n[t].call(e.exports, e, e.exports, i),
e.l = !0,
e.exports
}
i.m = n,
i.c = r,
i.d = function(t, e, n) {
i.o(t, e) || Object.defineProperty(t, e, {
enumerable: !0,
get: n
})
}
,
i.r = function(t) {
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(t, Symbol.toStringTag, {
value: "Module"
}),
Object.defineProperty(t, "__esModule", {
value: !0
})
}
,
i.t = function(e, t) {
if (1 & t && (e = i(e)),
8 & t)
return e;
if (4 & t && "object" == typeof e && e && e.__esModule)
return e;
var n = Object.create(null);
if (i.r(n),
Object.defineProperty(n, "default", {
enumerable: !0,
value: e
}),
2 & t && "string" != typeof e)
for (var r in e)
i.d(n, r, function(t) {
return e[t]
}
.bind(null, r));
return n
}
,
i.n = function(t) {
var e = t && t.__esModule ? function() {
return t.default
}
: function() {
return t
}
;
return i.d(e, "a", e),
e
}
,
i.o = function(t, e) {
return Object.prototype.hasOwnProperty.call(t, e)
}
,
i.p = "/";
//i(i.s = 50);
aaa = i;
}(
{
50:function(t, e, n) {
"use strict";
n.r(e);
function r(t) {
var o = this;
this.refreshTicket = function () {
o.getTicket(),
o.interval && clearInterval(o.interval),
o.interval = setInterval(function () {
o.getTicket()
}, 6e5)
}
,
this.getTicket = function () {
var t = {
service: o.service,
version: o.serviceVersion
};
return new Promise(function (n) {
Object(l.fetch)({
url: "" + o.domain + u.APIEndpoint.init,
method: "POST",
data: t
}).then(function (t) {
if (n(),
t.data.success) {
var e = t.data.publicKey.key;
o.ec.setPublicKey(e),
o.loginTicketId = t.data.loginTicketId,
o.publicKey = e,
o.encodeVersion = t.data.publicKey.version
} else
Object(c.sendFee)({
detail: t,
errorName: "passport-init-error"
})
})
}
)
}
,
this.getRiskInfo = function (t) {
var e = {
name: "",
version: ""
}
, n = "";
try {
var r = new a.a;
e = r.getOS(),
n = r.getUA()
} catch (t) {
Object(c.sendFee)({
detail: {
error: t
},
errorName: "ua-parser-error"
})
}
var i = {
ua: n,
clientSource: "pc",
os: e.name,
osVersion: e.version
};
return Object.assign({}, i, t)
}
,
this.passwordLogin = function (t, e) {
t.encodeVersion = o.encodeVersion;
var n = {};
e.clickPos && (n = o.getRiskInfo(Object.assign({}, e.clickPos))),
o.publicKey && (t.password = o.ec.encrypt(t.password));
var r = {
service: o.service,
mainAuthMethodName: u.mainAuthMethodName.PASSWORD,
accountSystem: o.accountSystem,
credential: t,
context: Object.assign({}, n),
loginTicketId: o.loginTicketId,
version: o.serviceVersion
};
return window.srcId && (r.srcId = window.srcId),
t.code && (r.mfaAuthMethodName = u.allianceMethods.security),
e.ticketMaxAge && (r.ticketMaxAge = e.ticketMaxAge),
new Promise(function (e, n) {
Object(l.fetch)({
url: "" + o.domain + u.APIEndpoint.auth,
method: "POST",
data: r
}).then(function (t) {
e(t),
o.sign = t.data.sign,
o.tgt = t.data.serviceTicket.id
}).catch(function (t) {
Object(c.sendFee)({
detail: {
error: t,
data: r
},
errorName: "passport-auth-error"
}),
n(t)
})
}
)
}
,
this.register = function (t, e) {
t.encodeVersion = o.encodeVersion;
var n = {};
e.clickPos && (n = o.getRiskInfo(Object.assign({}, e.clickPos))),
o.publicKey && (t.password = o.ec.encrypt(t.password));
var r = {
service: o.service,
accountSystem: o.accountSystem,
context: Object.assign({}, n),
displayName: Object(l.maskPhoneNumber)(t.phoneNum),
registerMethodName: "security-code",
credential: t
};
return window.srcId && (r.srcId = window.srcId),
new Promise(function (e, n) {
Object(l.fetch)({
url: "" + o.domain + u.APIEndpoint.register,
method: "POST",
data: r
}).then(function (t) {
e(t)
}).catch(function (t) {
Object(c.sendFee)({
detail: {
error: t,
data: r
},
errorName: "passport-register-error"
}),
n(t)
})
}
)
}
,
this.logout = function (r) {
return new Promise(function (e, n) {
Object(l.fetch)({
url: "" + o.domain + u.APIEndpoint.logout,
method: "POST",
data: {
context: {
sign: r && r.context && r.context.sign ? r.context.sign : o.sign
},
tgt: r && r.tgt ? r.tgt : o.tgt
}
}).then(function (t) {
e(t)
}).catch(function (t) {
Object(c.sendFee)({
detail: {
error: t,
data: {
service: o.service,
tgt: r && r.tgt ? r.tgt : o.tgt
}
},
errorName: "passport-logout-error"
}),
n(t)
})
}
)
}
,
this.ec = new s.a,
ddd = this;
this.loginTicketId = "";
this.publicKey = "";
this.encodeVersion = "";
this.sign = "";
this.tgt = "";
}
var i = n(5)
, s = n.n(i)
, o = n(19)
, a = n.n(o)
, c = n(2)
, u = n(0)
, l = n(1)
, h = function(t, s, a, c) {
return new (a = a || Promise)(function(e, n) {
function r(t) {
try {
o(c.next(t))
} catch (t) {
n(t)
}
}
function i(t) {
try {
o(c.throw(t))
} catch (t) {
n(t)
}
}
function o(t) {
t.done ? e(t.value) : function(e) {
return e instanceof a ? e : new a(function(t) {
t(e)
}
)
}(t.value).then(r, i)
}
o((c = c.apply(t, s || [])).next())
}
)
}
, f = function(n, r) {
var i, o, s, t, a = {
label: 0,
sent: function() {
if (1 & s[0])
throw s[1];
return s[1]
},
trys: [],
ops: []
};
return t = {
next: e(0),
throw: e(1),
return: e(2)
},
"function" == typeof Symbol && (t[Symbol.iterator] = function() {
return this
}
),
t;
function e(e) {
return function(t) {
return function(e) {
if (i)
throw new TypeError("Generator is already executing.");
for (; a; )
try {
if (i = 1,
o && (s = 2 & e[0] ? o.return : e[0] ? o.throw || ((s = o.return) && s.call(o),
0) : o.next) && !(s = s.call(o, e[1])).done)
return s;
switch (o = 0,
s && (e = [2 & e[0], s.value]),
e[0]) {
case 0:
case 1:
s = e;
break;
case 4:
return a.label++,
{
value: e[1],
done: !1
};
case 5:
a.label++,
o = e[1],
e = [0];
continue;
case 7:
e = a.ops.pop(),
a.trys.pop();
continue;
default:
if (!(s = 0 < (s = a.trys).length && s[s.length - 1]) && (6 === e[0] || 2 === e[0])) {
a = 0;
continue
}
if (3 === e[0] && (!s || e[1] > s[0] && e[1] < s[3])) {
a.label = e[1];
break
}
if (6 === e[0] && a.label < s[1]) {
a.label = s[1],
s = e;
break
}
if (s && a.label < s[2]) {
a.label = s[2],
a.ops.push(e);
break
}
s[2] && a.ops.pop(),
a.trys.pop();
continue
}
e = r.call(n, a)
} catch (t) {
e = [6, t],
o = 0
} finally {
i = s = 0
}
if (5 & e[0])
throw e[1];
return {
value: e[0] ? e[1] : void 0,
done: !0
}
}([e, t])
}
}
};
e.default = r
},
5 :function(t, e, n) {
!function(t) {
"use strict";
var e = "0123456789abcdefghijklmnopqrstuvwxyz";
function c(t) {
return e.charAt(t)
}
function n(t, e) {
return t & e
}
function u(t, e) {
return t | e
}
function r(t, e) {
return t ^ e
}
function i(t, e) {
return t & ~e
}
function o(t) {
if (0 == t)
return -1;
var e = 0;
return 0 == (65535 & t) && (t >>= 16,
e += 16),
0 == (255 & t) && (t >>= 8,
e += 8),
0 == (15 & t) && (t >>= 4,
e += 4),
0 == (3 & t) && (t >>= 2,
e += 2),
0 == (1 & t) && ++e,
e
}
function s(t) {
for (var e = 0; 0 != t; )
t &= t - 1,
++e;
return e
}
var a = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function l(t) {
var e, n, r = "";
for (e = 0; e + 3 <= t.length; e += 3)
n = parseInt(t.substring(e, e + 3), 16),
r += a.charAt(n >> 6) + a.charAt(63 & n);
for (e + 1 == t.length ? (n = parseInt(t.substring(e, e + 1), 16),
r += a.charAt(n << 2)) : e + 2 == t.length && (n = parseInt(t.substring(e, e + 2), 16),
r += a.charAt(n >> 2) + a.charAt((3 & n) << 4)); 0 < (3 & r.length); )
r += "=";
return r
}
function h(t) {
var e, n = "", r = 0, i = 0;
for (e = 0; e < t.length && "=" != t.charAt(e); ++e) {
var o = a.indexOf(t.charAt(e));
o < 0 || (r = 0 == r ? (n += c(o >> 2),
i = 3 & o,
1) : 1 == r ? (n += c(i << 2 | o >> 4),
i = 15 & o,
2) : 2 == r ? (n += c(i),
n += c(o >> 2),
i = 3 & o,
3) : (n += c(i << 2 | o >> 4),
n += c(15 & o),
0))
}
return 1 == r && (n += c(i << 2)),
n
}
var f, d = function(t, e) {
return (d = Object.setPrototypeOf || {
__proto__: []
}instanceof Array && function(t, e) {
t.__proto__ = e
}
|| function(t, e) {
for (var n in e)
e.hasOwnProperty(n) && (t[n] = e[n])
}
)(t, e)
};
var p, g = {
decode: function(t) {
var e;
if (void 0 === f) {
var n = "0123456789ABCDEF"
, r = " \f\n\r\t \u2028\u2029";
for (f = {},
e = 0; e < 16; ++e)
f[n.charAt(e)] = e;
for (n = n.toLowerCase(),
e = 10; e < 16; ++e)
f[n.charAt(e)] = e;
for (e = 0; e < r.length; ++e)
f[r.charAt(e)] = -1
}
var i = []
, o = 0
, s = 0;
for (e = 0; e < t.length; ++e) {
var a = t.charAt(e);
if ("=" == a)
break;
if (-1 != (a = f[a])) {
if (void 0 === a)
throw new Error("Illegal character at offset " + e);
o |= a,
2 <= ++s ? (i[i.length] = o,
s = o = 0) : o <<= 4
}
}
if (s)
throw new Error("Hex encoding incomplete: 4 bits missing");
return i
}
}, m = {
decode: function(t) {
var e;
if (void 0 === p) {
var n = "= \f\n\r\t \u2028\u2029";
for (p = Object.create(null),
e = 0; e < 64; ++e)
p["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(e)] = e;
for (e = 0; e < n.length; ++e)
p[n.charAt(e)] = -1
}
var r = []
, i = 0
, o = 0;
for (e = 0; e < t.length; ++e) {
var s = t.charAt(e);
if ("=" == s)
break;
if (-1 != (s = p[s])) {
if (void 0 === s)
throw new Error("Illegal character at offset " + e);
i |= s,
4 <= ++o ? (r[r.length] = i >> 16,
r[r.length] = i >> 8 & 255,
r[r.length] = 255 & i,
o = i = 0) : i <<= 6
}
}
switch (o) {
case 1:
throw new Error("Base64 encoding incomplete: at least 2 bits missing");
case 2:
r[r.length] = i >> 10;
break;
case 3:
r[r.length] = i >> 16,
r[r.length] = i >> 8 & 255
}
return r
},
re: /-----BEGIN [^-]+-----([A-Za-z0-9+\/=\s]+)-----END [^-]+-----|begin-base64[^\n]+\n([A-Za-z0-9+\/=\s]+)====/,
unarmor: function(t) {
var e = m.re.exec(t);
if (e)
if (e[1])
t = e[1];
else {
if (!e[2])
throw new Error("RegExp out of sync");
t = e[2]
}
return m.decode(t)
}
}, v = 1e13, y = function() {
function t(t) {
this.buf = [+t || 0]
}
return t.prototype.mulAdd = function(t, e) {
var n, r, i = this.buf, o = i.length;
for (n = 0; n < o; ++n)
(r = i[n] * t + e) < v ? e = 0 : r -= (e = 0 | r / v) * v,
i[n] = r;
0 < e && (i[n] = e)
}
,
t.prototype.sub = function(t) {
var e, n, r = this.buf, i = r.length;
for (e = 0; e < i; ++e)
n = r[e] - t,
t = n < 0 ? (n += v,
1) : 0,
r[e] = n;
for (; 0 === r[r.length - 1]; )
r.pop()
}
,
t.prototype.toString = function(t) {
if (10 != (t || 10))
throw new Error("only base 10 is supported");
for (var e = this.buf, n = e[e.length - 1].toString(), r = e.length - 2; 0 <= r; --r)
n += (v + e[r]).toString().substring(1);
return n
}
,
t.prototype.valueOf = function() {
for (var t = this.buf, e = 0, n = t.length - 1; 0 <= n; --n)
e = e * v + t[n];
return e
}
,
t.prototype.simplify = function() {
var t = this.buf;
return 1 == t.length ? t[0] : this
}
,
t
}(), 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)?)?$/;
function T(t, e) {
return t.length > e && (t = t.substring(0, e) + b),
t
}
var E, S = function() {
function n(t, e) {
this.hexDigits = "0123456789ABCDEF",
t instanceof n ? (this.enc = t.enc,
this.pos = t.pos) : (this.enc = t,
this.pos = e)
}
return n.prototype.get = function(t) {
if (void 0 === t && (t = this.pos++),
t >= this.enc.length)
throw new Error("Requesting byte offset " + t + " on a stream of length " + this.enc.length);
return "string" == typeof this.enc ? this.enc.charCodeAt(t) : this.enc[t]
}
,
n.prototype.hexByte = function(t) {
return this.hexDigits.charAt(t >> 4 & 15) + this.hexDigits.charAt(15 & t)
}
,
n.prototype.hexDump = function(t, e, n) {
for (var r = "", i = t; i < e; ++i)
if (r += this.hexByte(this.get(i)),
!0 !== n)
switch (15 & i) {
case 7:
r += " ";
break;
case 15:
r += "\n";
break;
default:
r += " "
}
return r
}
,
n.prototype.isASCII = function(t, e) {
for (var n = t; n < e; ++n) {
var r = this.get(n);
if (r < 32 || 176 < r)
return !1
}
return !0
}
,
n.prototype.parseStringISO = function(t, e) {
for (var n = "", r = t; r < e; ++r)
n += String.fromCharCode(this.get(r));
return n
}
,
n.prototype.parseStringUTF = function(t, e) {
for (var n = "", r = t; r < e; ) {
var i = this.get(r++);
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++))
}
return n
}
,
n.prototype.parseStringBMP = function(t, e) {
for (var n, r, i = "", o = t; o < e; )
n = this.get(o++),
r = this.get(o++),
i += String.fromCharCode(n << 8 | r);
return i
}
,
n.prototype.parseTime = function(t, e, n) {
var r = this.parseStringISO(t, e)
, i = (n ? w : x).exec(r);
return i ? (n && (i[1] = +i[1],
i[1] += +i[1] < 70 ? 2e3 : 1900),
r = i[1] + "-" + i[2] + "-" + i[3] + " " + i[4],
i[5] && (r += ":" + i[5],
i[6] && (r += ":" + i[6],
i[7] && (r += "." + i[7]))),
i[8] && (r += " UTC",
"Z" != i[8] && (r += i[8],
i[9] && (r += ":" + i[9]))),
r) : "Unrecognized time: " + r
}
,
n.prototype.parseInteger = function(t, e) {
for (var n, r = this.get(t), i = 127 < r, o = i ? 255 : 0, s = ""; r == o && ++t < e; )
r = this.get(t);
if (0 === (n = e - t))
return i ? -1 : 0;
if (4 < n) {
for (s = r,
n <<= 3; 0 == (128 & (+s ^ o)); )
s = +s << 1,
--n;
s = "(" + n + " bit)\n"
}
i && (r -= 256);
for (var a = new y(r), c = t + 1; c < e; ++c)
a.mulAdd(256, this.get(c));
return s + a.toString()
}
,
n.prototype.parseBitString = function(t, e, n) {
for (var r = this.get(t), i = (e - t - 1 << 3) - r, o = "(" + i + " bit)\n", s = "", a = t + 1; a < e; ++a) {
for (var c = this.get(a), u = a == e - 1 ? r : 0, l = 7; u <= l; --l)
s += c >> l & 1 ? "1" : "0";
if (s.length > n)
return o + T(s, n)
}
return o + s
}
,
n.prototype.parseOctetString = function(t, e, n) {
if (this.isASCII(t, e))
return T(this.parseStringISO(t, e), n);
var r = e - t
, i = "(" + r + " byte)\n";
(n /= 2) < r && (e = t + n);
for (var o = t; o < e; ++o)
i += this.hexByte(this.get(o));
return n < r && (i += b),
i
}
,
n.prototype.parseOID = function(t, e, n) {
for (var r = "", i = new y, o = 0, s = t; s < e; ++s) {
var a = this.get(s);
if (i.mulAdd(128, 127 & a),
o += 7,
!(128 & a)) {
if ("" === r)
if ((i = i.simplify())instanceof y)
i.sub(80),
r = "2." + i.toString();
else {
var c = i < 80 ? i < 40 ? 0 : 1 : 2;
r = c + "." + (i - 40 * c)
}
else
r += "." + i.toString();
if (r.length > n)
return T(r, n);
i = new y,
o = 0
}
}
return 0 < o && (r += ".incomplete"),
r
}
,
n
}(), _ = function() {
function l(t, e, n, r, i) {
if (!(r instanceof A))
throw new Error("Invalid tag value.");
this.stream = t,
this.header = e,
this.length = n,
this.tag = r,
this.sub = i
}
return l.prototype.typeName = function() {
switch (this.tag.tagClass) {
case 0:
switch (this.tag.tagNumber) {
case 0:
return "EOC";
case 1:
return "BOOLEAN";
case 2:
return "INTEGER";
case 3:
return "BIT_STRING";
case 4:
return "OCTET_STRING";
case 5:
return "NULL";
case 6:
return "OBJECT_IDENTIFIER";
case 7:
return "ObjectDescriptor";
case 8:
return "EXTERNAL";
case 9:
return "REAL";
case 10:
return "ENUMERATED";
case 11:
return "EMBEDDED_PDV";
case 12:
return "UTF8String";
case 16:
return "SEQUENCE";
case 17:
return "SET";
case 18:
return "NumericString";
case 19:
return "PrintableString";
case 20:
return "TeletexString";
case 21:
return "VideotexString";
case 22:
return "IA5String";
case 23:
return "UTCTime";
case 24:
return "GeneralizedTime";
case 25:
return "GraphicString";
case 26:
return "VisibleString";
case 27:
return "GeneralString";
case 28:
return "UniversalString";
case 30:
return "BMPString"
}
return "Universal_" + this.tag.tagNumber.toString();
case 1:
return "Application_" + this.tag.tagNumber.toString();
case 2:
return "[" + this.tag.tagNumber.toString() + "]";
case 3:
return "Private_" + this.tag.tagNumber.toString()
}
}
,
l.prototype.content = function(t) {
if (void 0 === this.tag)
return null;
void 0 === t && (t = 1 / 0);
var e = this.posContent()
, n = Math.abs(this.length);
if (!this.tag.isUniversal())
return null !== this.sub ? "(" + this.sub.length + " elem)" : this.stream.parseOctetString(e, e + n, t);
switch (this.tag.tagNumber) {
case 1:
return 0 === this.stream.get(e) ? "false" : "true";
case 2:
return this.stream.parseInteger(e, e + n);
case 3:
return this.sub ? "(" + this.sub.length + " elem)" : this.stream.parseBitString(e, e + n, t);
case 4:
return this.sub ? "(" + this.sub.length + " elem)" : this.stream.parseOctetString(e, e + n, t);
case 6:
return this.stream.parseOID(e, e + n, t);
case 16:
case 17:
return null !== this.sub ? "(" + this.sub.length + " elem)" : "(no elem)";
case 12:
return T(this.stream.parseStringUTF(e, e + n), t);
case 18:
case 19:
case 20:
case 21:
case 22:
case 26:
return T(this.stream.parseStringISO(e, e + n), t);
case 30:
return T(this.stream.parseStringBMP(e, e + n), t);
case 23:
case 24:
return this.stream.parseTime(e, e + n, 23 == this.tag.tagNumber)
}
return null
}
,
l.prototype.toString = function() {
return this.typeName() + "@" + this.stream.pos + "[header:" + this.header + ",length:" + this.length + ",sub:" + (null === this.sub ? "null" : this.sub.length) + "]"
}
,
l.prototype.toPrettyString = function(t) {
void 0 === t && (t = "");
var e = t + this.typeName() + " @" + this.stream.pos;
if (0 <= this.length && (e += "+"),
e += this.length,
this.tag.tagConstructed ? e += " (constructed)" : !this.tag.isUniversal() || 3 != this.tag.tagNumber && 4 != this.tag.tagNumber || null === this.sub || (e += " (encapsulates)"),
e += "\n",
null !== this.sub) {
t += " ";
for (var n = 0, r = this.sub.length; n < r; ++n)
e += this.sub[n].toPrettyString(t)
}
return e
}
,
l.prototype.posStart = function() {
return this.stream.pos
}
,
l.prototype.posContent = function() {
return this.stream.pos + this.header
}
,
l.prototype.posEnd = function() {
return this.stream.pos + this.header + Math.abs(this.length)
}
,
l.prototype.toHexString = function() {
return this.stream.hexDump(this.posStart(), this.posEnd(), !0)
}
,
l.decodeLength = function(t) {
var e = t.get()
, n = 127 & e;
if (n == e)
return n;
if (6 < n)
throw new Error("Length over 48 bits not supported at position " + (t.pos - 1));
if (0 == n)
return null;
for (var r = e = 0; r < n; ++r)
e = 256 * e + t.get();
return e
}
,
l.prototype.getHexStringValue = function() {
var t = this.toHexString()
, e = 2 * this.header
, n = 2 * this.length;
return t.substr(e, n)
}
,
l.decode = function(t) {
var r;
r = t instanceof S ? t : new S(t,0);
var e = new S(r)
, n = new A(r)
, i = l.decodeLength(r)
, o = r.pos
, s = o - e.pos
, a = null
, c = function() {
var t = [];
if (null !== i) {
for (var e = o + i; r.pos < e; )
t[t.length] = l.decode(r);
if (r.pos != e)
throw new Error("Content size is not correct for container starting at offset " + o)
} else
try {
for (; ; ) {
var n = l.decode(r);
if (n.tag.isEOC())
break;
t[t.length] = n
}
i = o - r.pos
} catch (t) {
throw new Error("Exception while decoding undefined length content: " + t)
}
return t
};
if (n.tagConstructed)
a = c();
else if (n.isUniversal() && (3 == n.tagNumber || 4 == n.tagNumber))
try {
if (3 == n.tagNumber && 0 != r.get())
throw new Error("BIT STRINGs with unused bits cannot encapsulate.");
a = c();
for (var u = 0; u < a.length; ++u)
if (a[u].tag.isEOC())
throw new Error("EOC is not supposed to be actual content.")
} catch (t) {
a = null
}
if (null === a) {
if (null === i)
throw new Error("We can't skip over an invalid tag with undefined length at offset " + o);
r.pos = o + Math.abs(i)
}
return new l(e,s,i,n,a)
}
,
l
}(), A = function() {
function t(t) {
var e = t.get();
if (this.tagClass = e >> 6,
this.tagConstructed = 0 != (32 & e),
this.tagNumber = 31 & e,
31 == this.tagNumber) {
for (var n = new y; e = t.get(),
n.mulAdd(128, 127 & e),
128 & e; )
;
this.tagNumber = n.simplify()
}
}
return t.prototype.isUniversal = function() {
return 0 === this.tagClass
}
,
t.prototype.isEOC = function() {
return 0 === this.tagClass && 0 === this.tagNumber
}
,
t
}(), 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() {
function b(t, e, n) {
null != t && ("number" == typeof t ? this.fromNumber(t, e, n) : null == e && "string" != typeof t ? this.fromString(t, 256) : this.fromString(t, e))
}
return b.prototype.toString = function(t) {
if (this.s < 0)
return "-" + this.negate().toString(t);
var e;
if (16 == t)
e = 4;
else if (8 == t)
e = 3;
else if (2 == t)
e = 1;
else if (32 == t)
e = 5;
else {
if (4 != t)
return this.toRadix(t);
e = 2
}
var n, r = (1 << e) - 1, i = !1, o = "", s = this.t, a = this.DB - s * this.DB % e;
if (0 < s--)
for (a < this.DB && 0 < (n = this[s] >> a) && (i = !0,
o = c(n)); 0 <= s; )
a < e ? (n = (this[s] & (1 << a) - 1) << e - a,
n |= this[--s] >> (a += this.DB - e)) : (n = this[s] >> (a -= e) & r,
a <= 0 && (a += this.DB,
--s)),
0 < n && (i = !0),
i && (o += c(n));
return i ? o : "0"
}
,
b.prototype.negate = function() {
var t = P();
return b.ZERO.subTo(this, t),
t
}
,
b.prototype.abs = function() {
return this.s < 0 ? this.negate() : this
}
,
b.prototype.compareTo = function(t) {
var e = this.s - t.s;
if (0 != e)
return e;
var n = this.t;
if (0 != (e = n - t.t))
return this.s < 0 ? -e : e;
for (; 0 <= --n; )
if (0 != (e = this[n] - t[n]))
return e;
return 0
}
,
b.prototype.bitLength = function() {
return this.t <= 0 ? 0 : this.DB * (this.t - 1) + U(this[this.t - 1] ^ this.s & this.DM)
}
,
b.prototype.mod = function(t) {
var e = P();
return this.abs().divRemTo(t, null, e),
this.s < 0 && 0 < e.compareTo(b.ZERO) && t.subTo(e, e),
e
}
,
b.prototype.modPowInt = function(t, e) {
var n;
return n = t < 256 || e.isEven() ? new O(e) : new R(e),
this.exp(t, n)
}
,
b.prototype.clone = function() {
var t = P();
return this.copyTo(t),
t
}
,
b.prototype.intValue = function() {
if (this.s < 0) {
if (1 == this.t)
return this[0] - this.DV;
if (0 == this.t)
return -1
} else {
if (1 == this.t)
return this[0];
if (0 == this.t)
return 0
}
return (this[1] & (1 << 32 - this.DB) - 1) << this.DB | this[0]
}
,
b.prototype.byteValue = function() {
return 0 == this.t ? this.s : this[0] << 24 >> 24
}
,
b.prototype.shortValue = function() {
return 0 == this.t ? this.s : this[0] << 16 >> 16
}
,
b.prototype.signum = function() {
return this.s < 0 ? -1 : this.t <= 0 || 1 == this.t && this[0] <= 0 ? 0 : 1
}
,
b.prototype.toByteArray = function() {
var t = this.t
, e = [];
e[0] = this.s;
var n, r = this.DB - t * this.DB % 8, i = 0;
if (0 < t--)
for (r < this.DB && (n = this[t] >> r) != (this.s & this.DM) >> r && (e[i++] = n | this.s << this.DB - r); 0 <= t; )
r < 8 ? (n = (this[t] & (1 << r) - 1) << 8 - r,
n |= this[--t] >> (r += this.DB - 8)) : (n = this[t] >> (r -= 8) & 255,
r <= 0 && (r += this.DB,
--t)),
0 != (128 & n) && (n |= -256),
0 == i && (128 & this.s) != (128 & n) && ++i,
(0 < i || n != this.s) && (e[i++] = n);
return e
}
,
b.prototype.equals = function(t) {
return 0 == this.compareTo(t)
}
,
b.prototype.min = function(t) {
return this.compareTo(t) < 0 ? this : t
}
,
b.prototype.max = function(t) {
return 0 < this.compareTo(t) ? this : t
}
,
b.prototype.and = function(t) {
var e = P();
return this.bitwiseTo(t, n, e),
e
}
,
b.prototype.or = function(t) {
var e = P();
return this.bitwiseTo(t, u, e),
e
}
,
b.prototype.xor = function(t) {
var e = P();
return this.bitwiseTo(t, r, e),
e
}
,
b.prototype.andNot = function(t) {
var e = P();
return this.bitwiseTo(t, i, e),
e
}
,
b.prototype.not = function() {
for (var t = P(), e = 0; e < this.t; ++e)
t[e] = this.DM & ~this[e];
return t.t = this.t,
t.s = ~this.s,
t
}
,
b.prototype.shiftLeft = function(t) {
var e = P();
return t < 0 ? this.rShiftTo(-t, e) : this.lShiftTo(t, e),
e
}
,
b.prototype.shiftRight = function(t) {
var e = P();
return t < 0 ? this.lShiftTo(-t, e) : this.rShiftTo(t, e),
e
}
,
b.prototype.getLowestSetBit = function() {
for (var t = 0; t < this.t; ++t)
if (0 != this[t])
return t * this.DB + o(this[t]);
return this.s < 0 ? this.t * this.DB : -1
}
,
b.prototype.bitCount = function() {
for (var t = 0, e = this.s & this.DM, n = 0; n < this.t; ++n)
t += s(this[n] ^ e);
return t
}
,
b.prototype.testBit = function(t) {
var e = Math.floor(t / this.DB);
return e >= this.t ? 0 != this.s : 0 != (this[e] & 1 << t % this.DB)
}
,
b.prototype.setBit = function(t) {
return this.changeBit(t, u)
}
,
b.prototype.clearBit = function(t) {
return this.changeBit(t, i)
}
,
b.prototype.flipBit = function(t) {
return this.changeBit(t, r)
}
,
b.prototype.add = function(t) {
var e = P();
return this.addTo(t, e),
e
}
,
b.prototype.subtract = function(t) {
var e = P();
return this.subTo(t, e),
e
}
,
b.prototype.multiply = function(t) {
var e = P();
return this.multiplyTo(t, e),
e
}
,
b.prototype.divide = function(t) {
var e = P();
return this.divRemTo(t, e, null),
e
}
,
b.prototype.remainder = function(t) {
var e = P();
return this.divRemTo(t, null, e),
e
}
,
b.prototype.divideAndRemainder = function(t) {
var e = P()
, n = P();
return this.divRemTo(t, e, n),
[e, n]
}
,
b.prototype.modPow = function(t, e) {
var n, r, i = t.bitLength(), o = q(1);
if (i <= 0)
return o;
n = i < 18 ? 1 : i < 48 ? 3 : i < 144 ? 4 : i < 768 ? 5 : 6,
r = i < 8 ? new O(e) : e.isEven() ? new I(e) : new R(e);
var s = []
, a = 3
, c = n - 1
, u = (1 << n) - 1;
if (s[1] = r.convert(this),
1 < n) {
var l = P();
for (r.sqrTo(s[1], l); a <= u; )
s[a] = P(),
r.mulTo(l, s[a - 2], s[a]),
a += 2
}
var h, f, d = t.t - 1, p = !0, g = P();
for (i = U(t[d]) - 1; 0 <= d; ) {
for (c <= i ? h = t[d] >> i - c & u : (h = (t[d] & (1 << i + 1) - 1) << c - i,
0 < d && (h |= t[d - 1] >> this.DB + i - c)),
a = n; 0 == (1 & h); )
h >>= 1,
--a;
if ((i -= a) < 0 && (i += this.DB,
--d),
p)
s[h].copyTo(o),
p = !1;
else {
for (; 1 < a; )
r.sqrTo(o, g),
r.sqrTo(g, o),
a -= 2;
0 < a ? r.sqrTo(o, g) : (f = o,
o = g,
g = f),
r.mulTo(g, s[h], o)
}
for (; 0 <= d && 0 == (t[d] & 1 << i); )
r.sqrTo(o, g),
f = o,
o = g,
g = f,
--i < 0 && (i = this.DB - 1,
--d)
}
return r.revert(o)
}
,
b.prototype.modInverse = function(t) {
var e = t.isEven();
if (this.isEven() && e || 0 == t.signum())
return b.ZERO;
for (var n = t.clone(), r = this.clone(), i = q(1), o = q(0), s = q(0), a = q(1); 0 != n.signum(); ) {
for (; n.isEven(); )
n.rShiftTo(1, n),
e ? (i.isEven() && o.isEven() || (i.addTo(this, i),
o.subTo(t, o)),
i.rShiftTo(1, i)) : o.isEven() || o.subTo(t, o),
o.rShiftTo(1, o);
for (; r.isEven(); )
r.rShiftTo(1, r),
e ? (s.isEven() && a.isEven() || (s.addTo(this, s),
a.subTo(t, a)),
s.rShiftTo(1, s)) : a.isEven() || a.subTo(t, a),
a.rShiftTo(1, a);
0 <= n.compareTo(r) ? (n.subTo(r, n),
e && i.subTo(s, i),
o.subTo(a, o)) : (r.subTo(n, r),
e && s.subTo(i, s),
a.subTo(o, a))
}
return 0 != r.compareTo(b.ONE) ? b.ZERO : 0 <= a.compareTo(t) ? a.subtract(t) : a.signum() < 0 ? (a.addTo(t, a),
a.signum() < 0 ? a.add(t) : a) : a
}
,
b.prototype.pow = function(t) {
return this.exp(t, new N)
}
,
b.prototype.gcd = function(t) {
var e = this.s < 0 ? this.negate() : this.clone()
, n = t.s < 0 ? t.negate() : t.clone();
if (e.compareTo(n) < 0) {
var r = e;
e = n,
n = r
}
var i = e.getLowestSetBit()
, o = n.getLowestSetBit();
if (o < 0)
return e;
for (i < o && (o = i),
0 < o && (e.rShiftTo(o, e),
n.rShiftTo(o, n)); 0 < e.signum(); )
0 < (i = e.getLowestSetBit()) && e.rShiftTo(i, e),
0 < (i = n.getLowestSetBit()) && n.rShiftTo(i, n),
0 <= e.compareTo(n) ? (e.subTo(n, e),
e.rShiftTo(1, e)) : (n.subTo(e, n),
n.rShiftTo(1, n));
return 0 < o && n.lShiftTo(o, n),
n
}
,
b.prototype.isProbablePrime = function(t) {
var e, n = this.abs();
if (1 == n.t && n[0] <= k[k.length - 1]) {
for (e = 0; e < k.length; ++e)
if (n[0] == k[e])
return !0;
return !1
}
if (n.isEven())
return !1;
for (e = 1; e < k.length; ) {
for (var r = k[e], i = e + 1; i < k.length && r < C; )
r *= k[i++];
for (r = n.modInt(r); e < i; )
if (r % k[e++] == 0)
return !1
}
return n.millerRabin(t)
}
,
b.prototype.copyTo = function(t) {
for (var e = this.t - 1; 0 <= e; --e)
t[e] = this[e];
t.t = this.t,
t.s = this.s
}
,
b.prototype.fromInt = function(t) {
this.t = 1,
this.s = t < 0 ? -1 : 0,
0 < t ? this[0] = t : t < -1 ? this[0] = t + this.DV : this.t = 0
}
,
b.prototype.fromString = function(t, e) {
var n;
if (16 == e)
n = 4;
else if (8 == e)
n = 3;
else if (256 == e)
n = 8;
else if (2 == e)
n = 1;
else if (32 == e)
n = 5;
else {
if (4 != e)
return void this.fromRadix(t, e);
n = 2
}
this.t = 0,
this.s = 0;
for (var r = t.length, i = !1, o = 0; 0 <= --r; ) {
var s = 8 == n ? 255 & +t[r] : V(t, r);
s < 0 ? "-" == t.charAt(r) && (i = !0) : (i = !1,
0 == o ? this[this.t++] = s : o + n > this.DB ? (this[this.t - 1] |= (s & (1 << this.DB - o) - 1) << o,
this[this.t++] = s >> this.DB - o) : this[this.t - 1] |= s << o,
(o += n) >= this.DB && (o -= this.DB))
}
8 == n && 0 != (128 & +t[0]) && (this.s = -1,
0 < o && (this[this.t - 1] |= (1 << this.DB - o) - 1 << o)),
this.clamp(),
i && b.ZERO.subTo(this, this)
}
,
b.prototype.clamp = function() {
for (var t = this.s & this.DM; 0 < this.t && this[this.t - 1] == t; )
--this.t
}
,
b.prototype.dlShiftTo = function(t, e) {
var n;
for (n = this.t - 1; 0 <= n; --n)
e[n + t] = this[n];
for (n = t - 1; 0 <= n; --n)
e[n] = 0;
e.t = this.t + t,
e.s = this.s
}
,
b.prototype.drShiftTo = function(t, e) {
for (var n = t; n < this.t; ++n)
e[n - t] = this[n];
e.t = Math.max(this.t - t, 0),
e.s = this.s
}
,
b.prototype.lShiftTo = function(t, e) {
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)
e[a + o + 1] = this[a] >> r | s,
s = (this[a] & i) << n;
for (var a = o - 1; 0 <= a; --a)
e[a] = 0;
e[o] = s,
e.t = this.t + o + 1,
e.s = this.s,
e.clamp()
}
,
b.prototype.rShiftTo = function(t, e) {
e.s = this.s;
var n = Math.floor(t / this.DB);
if (n >= this.t)
e.t = 0;
else {
var r = t % this.DB
, i = this.DB - r
, o = (1 << r) - 1;
e[0] = this[n] >> r;
for (var s = n + 1; s < this.t; ++s)
e[s - n - 1] |= (this[s] & o) << i,
e[s - n] = this[s] >> r;
0 < r && (e[this.t - n - 1] |= (this.s & o) << i),
e.t = this.t - n,
e.clamp()
}
}
,
b.prototype.subTo = function(t, e) {
for (var n = 0, r = 0, i = Math.min(t.t, this.t); n < i; )
r += this[n] - t[n],
e[n++] = r & this.DM,
r >>= this.DB;
if (t.t < this.t) {
for (r -= t.s; n < this.t; )
r += this[n],
e[n++] = r & this.DM,
r >>= this.DB;
r += this.s
} else {
for (r += this.s; n < t.t; )
r -= t[n],
e[n++] = r & this.DM,
r >>= this.DB;
r -= t.s
}
e.s = r < 0 ? -1 : 0,
r < -1 ? e[n++] = this.DV + r : 0 < r && (e[n++] = r),
e.t = n,
e.clamp()
}
,
b.prototype.multiplyTo = function(t, e) {
var n = this.abs()
, r = t.abs()
, i = n.t;
for (e.t = i + r.t; 0 <= --i; )
e[i] = 0;
for (i = 0; i < r.t; ++i)
e[i + n.t] = n.am(0, r[i], e, i, 0, n.t);
e.s = 0,
e.clamp(),
this.s != t.s && b.ZERO.subTo(e, e)
}
,
b.prototype.squareTo = function(t) {
for (var e = this.abs(), n = t.t = 2 * e.t; 0 <= --n; )
t[n] = 0;
for (n = 0; n < e.t - 1; ++n) {
var r = e.am(n, e[n], t, 2 * n, 0, 1);
(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,
t[n + e.t + 1] = 1)
}
0 < t.t && (t[t.t - 1] += e.am(n, e[n], t, 2 * n, 0, 1)),
t.s = 0,
t.clamp()
}
,
b.prototype.divRemTo = function(t, e, n) {
var r = t.abs();
if (!(r.t <= 0)) {
var i = this.abs();
if (i.t < r.t)
return null != e && e.fromInt(0),
void (null != n && this.copyTo(n));
null == n && (n = P());
var o = P()
, s = this.s
, a = t.s
, c = this.DB - U(r[r.t - 1]);
0 < c ? (r.lShiftTo(c, o),
i.lShiftTo(c, n)) : (r.copyTo(o),
i.copyTo(n));
var u = o.t
, l = o[u - 1];
if (0 != l) {
var h = l * (1 << this.F1) + (1 < u ? o[u - 2] >> this.F2 : 0)
, f = this.FV / h
, d = (1 << this.F1) / h
, p = 1 << this.F2
, g = n.t
, m = g - u
, v = null == e ? P() : e;
for (o.dlShiftTo(m, v),
0 <= n.compareTo(v) && (n[n.t++] = 1,
n.subTo(v, n)),
b.ONE.dlShiftTo(u, v),
v.subTo(o, o); o.t < u; )
o[o.t++] = 0;
for (; 0 <= --m; ) {
var y = n[--g] == l ? this.DM : Math.floor(n[g] * f + (n[g - 1] + p) * d);
if ((n[g] += o.am(0, y, n, m, 0, u)) < y)
for (o.dlShiftTo(m, v),
n.subTo(v, n); n[g] < --y; )
n.subTo(v, n)
}
null != e && (n.drShiftTo(u, e),
s != a && b.ZERO.subTo(e, e)),
n.t = u,
n.clamp(),
0 < c && n.rShiftTo(c, n),
s < 0 && b.ZERO.subTo(n, n)
}
}
}
,
b.prototype.invDigit = function() {
if (this.t < 1)
return 0;
var t = this[0];
if (0 == (1 & t))
return 0;
var e = 3 & t;
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
}
,
b.prototype.isEven = function() {
return 0 == (0 < this.t ? 1 & this[0] : this.s)
}
,
b.prototype.exp = function(t, e) {
if (4294967295 < t || t < 1)
return b.ONE;
var n = P()
, r = P()
, i = e.convert(this)
, o = U(t) - 1;
for (i.copyTo(n); 0 <= --o; )
if (e.sqrTo(n, r),
0 < (t & 1 << o))
e.mulTo(r, i, n);
else {
var s = n;
n = r,
r = s
}
return e.revert(n)
}
,
b.prototype.chunkSize = function(t) {
return Math.floor(Math.LN2 * this.DB / Math.log(t))
}
,
b.prototype.toRadix = function(t) {
if (null == t && (t = 10),
0 == this.signum() || t < 2 || 36 < t)
return "0";
var e = this.chunkSize(t)
, n = Math.pow(t, e)
, r = q(n)
, i = P()
, o = P()
, s = "";
for (this.divRemTo(r, i, o); 0 < i.signum(); )
s = (n + o.intValue()).toString(t).substr(1) + s,
i.divRemTo(r, i, o);
return o.intValue().toString(t) + s
}
,
b.prototype.fromRadix = function(t, e) {
this.fromInt(0),
null == e && (e = 10);
for (var n = this.chunkSize(e), r = Math.pow(e, n), i = !1, o = 0, s = 0, a = 0; a < t.length; ++a) {
var c = V(t, a);
c < 0 ? "-" == t.charAt(a) && 0 == this.signum() && (i = !0) : (s = e * s + c,
++o >= n && (this.dMultiply(r),
this.dAddOffset(s, 0),
s = o = 0))
}
0 < o && (this.dMultiply(Math.pow(e, o)),
this.dAddOffset(s, 0)),
i && b.ZERO.subTo(this, this)
}
,
b.prototype.fromNumber = function(t, e, n) {
if ("number" == typeof e)
if (t < 2)
this.fromInt(1);
else
for (this.fromNumber(t, n),
this.testBit(t - 1) || this.bitwiseTo(b.ONE.shiftLeft(t - 1), u, this),
this.isEven() && this.dAddOffset(1, 0); !this.isProbablePrime(e); )
this.dAddOffset(2, 0),
this.bitLength() > t && this.subTo(b.ONE.shiftLeft(t - 1), this);
else {
var r = []
, i = 7 & t;
r.length = 1 + (t >> 3),
e.nextBytes(r),
0 < i ? r[0] &= (1 << i) - 1 : r[0] = 0,
this.fromString(r, 256)
}
}
,
b.prototype.bitwiseTo = function(t, e, n) {
var r, i, o = Math.min(t.t, this.t);
for (r = 0; r < o; ++r)
n[r] = e(this[r], t[r]);
if (t.t < this.t) {
for (i = t.s & this.DM,
r = o; r < this.t; ++r)
n[r] = e(this[r], i);
n.t = this.t
} else {
for (i = this.s & this.DM,
r = o; r < t.t; ++r)
n[r] = e(i, t[r]);
n.t = t.t
}
n.s = e(this.s, t.s),
n.clamp()
}
,
b.prototype.changeBit = function(t, e) {
var n = b.ONE.shiftLeft(t);
return this.bitwiseTo(n, e, n),
n
}
,
b.prototype.addTo = function(t, e) {
for (var n = 0, r = 0, i = Math.min(t.t, this.t); n < i; )
r += this[n] + t[n],
e[n++] = r & this.DM,
r >>= this.DB;
if (t.t < this.t) {
for (r += t.s; n < this.t; )
r += this[n],
e[n++] = r & this.DM,
r >>= this.DB;
r += this.s
} else {
for (r += this.s; n < t.t; )
r += t[n],
e[n++] = r & this.DM,
r >>= this.DB;
r += t.s
}
e.s = r < 0 ? -1 : 0,
0 < r ? e[n++] = r : r < -1 && (e[n++] = this.DV + r),
e.t = n,
e.clamp()
}
,
b.prototype.dMultiply = function(t) {
this[this.t] = this.am(0, t - 1, this, 0, 0, this.t),
++this.t,
this.clamp()
}
,
b.prototype.dAddOffset = function(t, e) {
if (0 != t) {
for (; this.t <= e; )
this[this.t++] = 0;
for (this[e] += t; this[e] >= this.DV; )
this[e] -= this.DV,
++e >= this.t && (this[this.t++] = 0),
++this[e]
}
}
,
b.prototype.multiplyLowerTo = function(t, e, n) {
var r = Math.min(this.t + t.t, e);
for (n.s = 0,
n.t = r; 0 < r; )
n[--r] = 0;
for (var i = n.t - this.t; r < i; ++r)
n[r + this.t] = this.am(0, t[r], n, r, 0, this.t);
for (var i = Math.min(t.t, e); r < i; ++r)
this.am(0, t[r], n, r, 0, e - r);
n.clamp()
}
,
b.prototype.multiplyUpperTo = function(t, e, n) {
--e;
var r = n.t = this.t + t.t - e;
for (n.s = 0; 0 <= --r; )
n[r] = 0;
for (r = Math.max(e - this.t, 0); r < t.t; ++r)
n[this.t + r - e] = this.am(e - r, t[r], n, 0, 0, this.t + r - e);
n.clamp(),
n.drShiftTo(1, n)
}
,
b.prototype.modInt = function(t) {
if (t <= 0)
return 0;
var e = this.DV % t
, n = this.s < 0 ? t - 1 : 0;
if (0 < this.t)
if (0 == e)
n = this[0] % t;
else
for (var r = this.t - 1; 0 <= r; --r)
n = (e * n + this[r]) % t;
return n
}
,
b.prototype.millerRabin = function(t) {
var e = this.subtract(b.ONE)
, n = e.getLowestSetBit();
if (n <= 0)
return !1;
var r = e.shiftRight(n);
k.length < (t = t + 1 >> 1) && (t = k.length);
for (var i = P(), o = 0; o < t; ++o) {
i.fromInt(k[Math.floor(Math.random() * k.length)]);
var s = i.modPow(r, this);
if (0 != s.compareTo(b.ONE) && 0 != s.compareTo(e)) {
for (var a = 1; a++ < n && 0 != s.compareTo(e); )
if (0 == (s = s.modPowInt(2, this)).compareTo(b.ONE))
return !1;
if (0 != s.compareTo(e))
return !1
}
}
return !0
}
,
b.prototype.square = function() {
var t = P();
return this.squareTo(t),
t
}
,
b.prototype.gcda = function(t, e) {
var n = this.s < 0 ? this.negate() : this.clone()
, r = t.s < 0 ? t.negate() : t.clone();
if (n.compareTo(r) < 0) {
var i = n;
n = r,
r = i
}
var o = n.getLowestSetBit()
, s = r.getLowestSetBit();
if (s < 0)
e(n);
else {
o < s && (s = o),
0 < s && (n.rShiftTo(s, n),
r.rShiftTo(s, r));
var a = function() {
0 < (o = n.getLowestSetBit()) && n.rShiftTo(o, n),
0 < (o = r.getLowestSetBit()) && r.rShiftTo(o, r),
0 <= n.compareTo(r) ? (n.subTo(r, n),
n.rShiftTo(1, n)) : (r.subTo(n, r),
r.rShiftTo(1, r)),
0 < n.signum() ? setTimeout(a, 0) : (0 < s && r.lShiftTo(s, r),
setTimeout(function() {
e(r)
}, 0))
};
setTimeout(a, 10)
}
}
,
b.prototype.fromNumberAsync = function(t, e, n, r) {
if ("number" == typeof e)
if (t < 2)
this.fromInt(1);
else {
this.fromNumber(t, n),
this.testBit(t - 1) || this.bitwiseTo(b.ONE.shiftLeft(t - 1), u, this),
this.isEven() && this.dAddOffset(1, 0);
var i = this
, o = function() {
i.dAddOffset(2, 0),
i.bitLength() > t && i.subTo(b.ONE.shiftLeft(t - 1), i),
i.isProbablePrime(e) ? setTimeout(function() {
r()
}, 0) : setTimeout(o, 0)
};
setTimeout(o, 0)
}
else {
var s = []
, a = 7 & t;
s.length = 1 + (t >> 3),
e.nextBytes(s),
0 < a ? s[0] &= (1 << a) - 1 : s[0] = 0,
this.fromString(s, 256)
}
}
,
b
}(), N = function() {
function t() {}
return t.prototype.convert = function(t) {
return t
}
,
t.prototype.revert = function(t) {
return t
}
,
t.prototype.mulTo = function(t, e, n) {
t.multiplyTo(e, n)
}
,
t.prototype.sqrTo = function(t, e) {
t.squareTo(e)
}
,
t
}(), O = function() {
function t(t) {
this.m = t
}
return t.prototype.convert = function(t) {
return t.s < 0 || 0 <= t.compareTo(this.m) ? t.mod(this.m) : t
}
,
t.prototype.revert = function(t) {
return t
}
,
t.prototype.reduce = function(t) {
t.divRemTo(this.m, null, t)
}
,
t.prototype.mulTo = function(t, e, n) {
t.multiplyTo(e, n),
this.reduce(n)
}
,
t.prototype.sqrTo = function(t, e) {
t.squareTo(e),
this.reduce(e)
}
,
t
}(), R = function() {
function t(t) {
this.m = t,
this.mp = t.invDigit(),
this.mpl = 32767 & this.mp,
this.mph = this.mp >> 15,
this.um = (1 << t.DB - 15) - 1,
this.mt2 = 2 * t.t
}
return t.prototype.convert = function(t) {
var e = P();
return t.abs().dlShiftTo(this.m.t, e),
e.divRemTo(this.m, null, e),
t.s < 0 && 0 < e.compareTo(D.ZERO) && this.m.subTo(e, e),
e
}
,
t.prototype.revert = function(t) {
var e = P();
return t.copyTo(e),
this.reduce(e),
e
}
,
t.prototype.reduce = function(t) {
for (; t.t <= this.mt2; )
t[t.t++] = 0;
for (var e = 0; e < this.m.t; ++e) {
var n = 32767 & t[e]
, r = n * this.mpl + ((n * this.mph + (t[e] >> 15) * this.mpl & this.um) << 15) & t.DM;
for (n = e + this.m.t,
t[n] += this.m.am(0, r, t, e, 0, this.m.t); t[n] >= t.DV; )
t[n] -= t.DV,
t[++n]++
}
t.clamp(),
t.drShiftTo(this.m.t, t),
0 <= t.compareTo(this.m) && t.subTo(this.m, t)
}
,
t.prototype.mulTo = function(t, e, n) {
t.multiplyTo(e, n),
this.reduce(n)
}
,
t.prototype.sqrTo = function(t, e) {
t.squareTo(e),
this.reduce(e)
}
,
t
}(), I = function() {
function t(t) {
this.m = t,
this.r2 = P(),
this.q3 = P(),
D.ONE.dlShiftTo(2 * t.t, this.r2),
this.mu = this.r2.divide(t)
}
return t.prototype.convert = function(t) {
if (t.s < 0 || t.t > 2 * this.m.t)
return t.mod(this.m);
if (t.compareTo(this.m) < 0)
return t;
var e = P();
return t.copyTo(e),
this.reduce(e),
e
}
,
t.prototype.revert = function(t) {
return t
}
,
t.prototype.reduce = function(t) {
for (t.drShiftTo(this.m.t - 1, this.r2),
t.t > this.m.t + 1 && (t.t = this.m.t + 1,
t.clamp()),
this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3),
this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2); t.compareTo(this.r2) < 0; )
t.dAddOffset(1, this.m.t + 1);
for (t.subTo(this.r2, t); 0 <= t.compareTo(this.m); )
t.subTo(this.m, t)
}
,
t.prototype.mulTo = function(t, e, n) {
t.multiplyTo(e, n),
this.reduce(n)
}
,
t.prototype.sqrTo = function(t, e) {
t.squareTo(e),
this.reduce(e)
}
,
t
}();
function P() {
return new D(null)
}
function j(t, e) {
return new D(t,e)
}
E = "Microsoft Internet Explorer" == navigator.appName ? (D.prototype.am = function(t, e, n, r, i, o) {
var s = 32767 & e
, a = e >> 15;
for (; 0 <= --o; ) {
var c = 32767 & this[t]
, u = this[t++] >> 15
, l = a * c + u * s;
c = s * c + ((32767 & l) << 15) + n[r] + (1073741823 & i),
i = (c >>> 30) + (l >>> 15) + a * u + (i >>> 30),
n[r++] = 1073741823 & c
}
return i
}
,
30) : "Netscape" != navigator.appName ? (D.prototype.am = function(t, e, n, r, i, o) {
for (; 0 <= --o; ) {
var s = e * this[t++] + n[r] + i;
i = Math.floor(s / 67108864),
n[r++] = 67108863 & s
}
return i
}
,
26) : (D.prototype.am = function(t, e, n, r, i, o) {
var s = 16383 & e
, a = e >> 14;
for (; 0 <= --o; ) {
var c = 16383 & this[t]
, u = this[t++] >> 14
, l = a * c + u * s;
c = s * c + ((16383 & l) << 14) + n[r] + i,
i = (c >> 28) + (l >> 14) + a * u,
n[r++] = 268435455 & c
}
return i
}
,
28),
D.prototype.DB = E,
D.prototype.DM = (1 << E) - 1,
D.prototype.DV = 1 << E;
D.prototype.FV = Math.pow(2, 52),
D.prototype.F1 = 52 - E,
D.prototype.F2 = 2 * E - 52;
var B, L, M = [];
for (B = "0".charCodeAt(0),
L = 0; L <= 9; ++L)
M[B++] = L;
for (B = "a".charCodeAt(0),
L = 10; L < 36; ++L)
M[B++] = L;
for (B = "A".charCodeAt(0),
L = 10; L < 36; ++L)
M[B++] = L;
function V(t, e) {
var n = M[t.charCodeAt(e)];
return null == n ? -1 : n
}
function q(t) {
var e = P();
return e.fromInt(t),
e
}
function U(t) {
var e, n = 1;
return 0 != (e = t >>> 16) && (t = e,
n += 16),
0 != (e = t >> 8) && (t = e,
n += 8),
0 != (e = t >> 4) && (t = e,
n += 4),
0 != (e = t >> 2) && (t = e,
n += 2),
0 != (e = t >> 1) && (t = e,
n += 1),
n
}
D.ZERO = q(0),
D.ONE = q(1);
var H = function() {
function t() {
this.i = 0,
this.j = 0,
this.S = []
}
return t.prototype.init = function(t) {
var e, n, r;
for (e = 0; e < 256; ++e)
this.S[e] = e;
for (e = n = 0; e < 256; ++e)
n = n + this.S[e] + t[e % t.length] & 255,
r = this.S[e],
this.S[e] = this.S[n],
this.S[n] = r;
this.i = 0,
this.j = 0
}
,
t.prototype.next = function() {
var t;
return this.i = this.i + 1 & 255,
this.j = this.j + this.S[this.i] & 255,
t = this.S[this.i],
this.S[this.i] = this.S[this.j],
this.S[this.j] = t,
this.S[t + this.S[this.i] & 255]
}
,
t
}();
var F, K, W = 256, z = null;
if (null == z) {
z = [];
var G = void (K = 0);
if (window.crypto && window.crypto.getRandomValues) {
var $ = new Uint32Array(256);
for (window.crypto.getRandomValues($),
G = 0; G < $.length; ++G)
z[K++] = 255 & $[G]
}
var X = function(t) {
if (this.count = this.count || 0,
256 <= this.count || W <= K)
window.removeEventListener ? window.removeEventListener("mousemove", X, !1) : window.detachEvent && window.detachEvent("onmousemove", X);
else
try {
var e = t.x + t.y;
z[K++] = 255 & e,
this.count += 1
} catch (t) {}
};
window.addEventListener ? window.addEventListener("mousemove", X, !1) : window.attachEvent && window.attachEvent("onmousemove", X)
}
function Q() {
if (null == F) {
for (F = new H; K < W; ) {
var t = Math.floor(65536 * Math.random());
z[K++] = 255 & t
}
for (F.init(z),
K = 0; K < z.length; ++K)
z[K] = 0;
K = 0
}
return F.next()
}
var J = function() {
function t() {}
return t.prototype.nextBytes = function(t) {
for (var e = 0; e < t.length; ++e)
t[e] = Q()
}
,
t
}();
var Z = function() {
function t() {
this.n = null,
this.e = 0,
this.d = null,
this.p = null,
this.q = null,
this.dmp1 = null,
this.dmq1 = null,
this.coeff = null
}
return t.prototype.doPublic = function(t) {
return t.modPowInt(this.e, this.n)
}
,
t.prototype.doPrivate = function(t) {
if (null == this.p || null == this.q)
return t.modPow(this.d, this.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; )
e = e.add(this.p);
return e.subtract(n).multiply(this.coeff).mod(this.p).multiply(this.q).add(n)
}
,
t.prototype.setPublic = function(t, e) {
null != t && null != e && 0 < t.length && 0 < e.length && (this.n = j(t, 16),
this.e = parseInt(e, 16))
}
,
t.prototype.encrypt = function(t) {
var e = function(t, e) {
if (e < t.length + 11)
return null;
var n = []
, r = t.length - 1;
for (; 0 <= r && 0 < e; ) {
var i = t.charCodeAt(r--);
i < 128 ? n[--e] = i : 127 < i && i < 2048 ? (n[--e] = 63 & i | 128,
n[--e] = i >> 6 | 192) : (n[--e] = 63 & i | 128,
n[--e] = i >> 6 & 63 | 128,
n[--e] = i >> 12 | 224)
}
n[--e] = 0;
var o = new J
, s = [];
for (; 2 < e; ) {
for (s[0] = 0; 0 == s[0]; )
o.nextBytes(s);
n[--e] = s[0]
}
return n[--e] = 2,
n[--e] = 0,
new D(n)
}(t, this.n.bitLength() + 7 >> 3);
if (null == e)
return null;
var n = this.doPublic(e);
if (null == n)
return null;
var r = n.toString(16);
return 0 == (1 & r.length) ? r : "0" + r
}
,
t.prototype.setPrivate = function(t, e, n) {
null != t && null != e && 0 < t.length && 0 < e.length && (this.n = j(t, 16),
this.e = parseInt(e, 16),
this.d = j(n, 16))
}
,
t.prototype.setPrivateEx = function(t, e, n, r, i, o, s, a) {
null != t && null != e && 0 < t.length && 0 < e.length && (this.n = j(t, 16),
this.e = parseInt(e, 16),
this.d = j(n, 16),
this.p = j(r, 16),
this.q = j(i, 16),
this.dmp1 = j(o, 16),
this.dmq1 = j(s, 16),
this.coeff = j(a, 16))
}
,
t.prototype.generate = function(t, e) {
var n = new J
, r = t >> 1;
this.e = parseInt(e, 16);
for (var i = new D(e,16); ; ) {
for (; this.p = new D(t - r,1,n),
0 != this.p.subtract(D.ONE).gcd(i).compareTo(D.ONE) || !this.p.isProbablePrime(10); )
;
for (; this.q = new D(r,1,n),
0 != this.q.subtract(D.ONE).gcd(i).compareTo(D.ONE) || !this.q.isProbablePrime(10); )
;
if (this.p.compareTo(this.q) <= 0) {
var o = this.p;
this.p = this.q,
this.q = o
}
var s = this.p.subtract(D.ONE)
, a = this.q.subtract(D.ONE)
, c = s.multiply(a);
if (0 == c.gcd(i).compareTo(D.ONE)) {
this.n = this.p.multiply(this.q),
this.d = i.modInverse(c),
this.dmp1 = this.d.mod(s),
this.dmq1 = this.d.mod(a),
this.coeff = this.q.modInverse(this.p);
break
}
}
}
,
t.prototype.decrypt = function(t) {
var e = j(t, 16)
, n = this.doPrivate(e);
return null == n ? null : function(t, e) {
var n = t.toByteArray()
, r = 0;
for (; r < n.length && 0 == n[r]; )
++r;
if (n.length - r != e - 1 || 2 != n[r])
return null;
++r;
for (; 0 != n[r]; )
if (++r >= n.length)
return null;
var i = "";
for (; ++r < n.length; ) {
var o = 255 & n[r];
o < 128 ? i += String.fromCharCode(o) : 191 < o && o < 224 ? (i += String.fromCharCode((31 & o) << 6 | 63 & n[r + 1]),
++r) : (i += String.fromCharCode((15 & o) << 12 | (63 & n[r + 1]) << 6 | 63 & n[r + 2]),
r += 2)
}
return i
}(n, this.n.bitLength() + 7 >> 3)
}
,
t.prototype.generateAsync = function(t, e, i) {
var o = new J
, s = t >> 1;
this.e = parseInt(e, 16);
var a = new D(e,16)
, c = this
, u = function() {
var e = function() {
if (c.p.compareTo(c.q) <= 0) {
var t = c.p;
c.p = c.q,
c.q = t
}
var e = c.p.subtract(D.ONE)
, n = c.q.subtract(D.ONE)
, r = e.multiply(n);
0 == r.gcd(a).compareTo(D.ONE) ? (c.n = c.p.multiply(c.q),
c.d = a.modInverse(r),
c.dmp1 = c.d.mod(e),
c.dmq1 = c.d.mod(n),
c.coeff = c.q.modInverse(c.p),
setTimeout(function() {
i()
}, 0)) : setTimeout(u, 0)
}
, n = function() {
c.q = P(),
c.q.fromNumberAsync(s, 1, o, function() {
c.q.subtract(D.ONE).gcda(a, function(t) {
0 == t.compareTo(D.ONE) && c.q.isProbablePrime(10) ? setTimeout(e, 0) : setTimeout(n, 0)
})
})
}
, r = function() {
c.p = P(),
c.p.fromNumberAsync(t - s, 1, o, function() {
c.p.subtract(D.ONE).gcda(a, function(t) {
0 == t.compareTo(D.ONE) && c.p.isProbablePrime(10) ? setTimeout(n, 0) : setTimeout(r, 0)
})
})
};
setTimeout(r, 0)
};
setTimeout(u, 0)
}
,
t.prototype.sign = function(t, e, n) {
var r = function(t) {
return Y[t] || ""
}(n)
, i = r + e(t).toString()
, o = function(t, e) {
if (e < t.length + 22)
return null;
for (var n = e - t.length - 6, r = "", i = 0; i < n; i += 2)
r += "ff";
return j("0001" + r + "00" + t, 16)
}(i, this.n.bitLength() / 4);
if (null == o)
return null;
var s = this.doPrivate(o);
if (null == s)
return null;
var a = s.toString(16);
return 0 == (1 & a.length) ? a : "0" + a
}
,
t.prototype.verify = function(t, e, n) {
var r = j(e, 16)
, i = this.doPublic(r);
if (null == i)
return null;
var o = i.toString(16).replace(/^1f+00/, "")
, s = function(t) {
for (var e in Y)
if (Y.hasOwnProperty(e)) {
var n = Y[e]
, r = n.length;
if (t.substr(0, r) == n)
return t.substr(r)
}
return t
}(o);
return s == n(t).toString()
}
,
t
}();
var Y = {
md2: "3020300c06082a864886f70d020205000410",
md5: "3020300c06082a864886f70d020505000410",
sha1: "3021300906052b0e03021a05000414",
sha224: "302d300d06096086480165030402040500041c",
sha256: "3031300d060960864801650304020105000420",
sha384: "3041300d060960864801650304020205000430",
sha512: "3051300d060960864801650304020305000440",
ripemd160: "3021300906052b2403020105000414"
};
var tt = {};
tt.lang = {
extend: function(t, e, n) {
if (!e || !t)
throw new Error("YAHOO.lang.extend failed, please check that all dependencies are included.");
var r = function() {};
if (r.prototype = e.prototype,
t.prototype = new r,
(t.prototype.constructor = t).superclass = e.prototype,
e.prototype.constructor == Object.prototype.constructor && (e.prototype.constructor = e),
n) {
var i;
for (i in n)
t.prototype[i] = n[i];
var o = function() {}
, s = ["toString", "valueOf"];
try {
/MSIE/.test(navigator.userAgent) && (o = function(t, e) {
for (i = 0; i < s.length; i += 1) {
var n = s[i]
, r = e[n];
"function" == typeof r && r != Object.prototype[n] && (t[n] = r)
}
}
)
} catch (t) {}
o(t.prototype, n)
}
}
};
var et = {};
void 0 !== et.asn1 && et.asn1 || (et.asn1 = {}),
et.asn1.ASN1Util = new function() {
this.integerToByteHex = function(t) {
var e = t.toString(16);
return e.length % 2 == 1 && (e = "0" + e),
e
}
,
this.bigIntToMinTwosComplementsHex = function(t) {
var e = t.toString(16);
if ("-" != e.substr(0, 1))
e.length % 2 == 1 ? e = "0" + e : e.match(/^[0-7]/) || (e = "00" + e);
else {
var n = e.substr(1)
, r = n.length;
r % 2 == 1 ? r += 1 : e.match(/^[0-7]/) || (r += 2);
for (var i = "", o = 0; o < r; o++)
i += "f";
var s = new D(i,16)
, a = s.xor(t).add(D.ONE);
e = a.toString(16).replace(/^-/, "")
}
return e
}
,
this.getPEMStringFromHex = function(t, e) {
return hextopem(t, e)
}
,
this.newObject = function(t) {
var e = et
, n = e.asn1
, r = n.DERBoolean
, i = n.DERInteger
, o = n.DERBitString
, s = n.DEROctetString
, a = n.DERNull
, c = n.DERObjectIdentifier
, u = n.DEREnumerated
, l = n.DERUTF8String
, h = n.DERNumericString
, f = n.DERPrintableString
, d = n.DERTeletexString
, p = n.DERIA5String
, g = n.DERUTCTime
, m = n.DERGeneralizedTime
, v = n.DERSequence
, y = n.DERSet
, b = n.DERTaggedObject
, w = n.ASN1Util.newObject
, x = Object.keys(t);
if (1 != x.length)
throw "key of param shall be only one.";
var T = x[0];
if (-1 == ":bool:int:bitstr:octstr:null:oid:enum:utf8str:numstr:prnstr:telstr:ia5str:utctime:gentime:seq:set:tag:".indexOf(":" + T + ":"))
throw "undefined key: " + T;
if ("bool" == T)
return new r(t[T]);
if ("int" == T)
return new i(t[T]);
if ("bitstr" == T)
return new o(t[T]);
if ("octstr" == T)
return new s(t[T]);
if ("null" == T)
return new a(t[T]);
if ("oid" == T)
return new c(t[T]);
if ("enum" == T)
return new u(t[T]);
if ("utf8str" == T)
return new l(t[T]);
if ("numstr" == T)
return new h(t[T]);
if ("prnstr" == T)
return new f(t[T]);
if ("telstr" == T)
return new d(t[T]);
if ("ia5str" == T)
return new p(t[T]);
if ("utctime" == T)
return new g(t[T]);
if ("gentime" == T)
return new m(t[T]);
if ("seq" == T) {
for (var E = t[T], S = [], _ = 0; _ < E.length; _++) {
var A = w(E[_]);
S.push(A)
}
return new v({
array: S
})
}
if ("set" == T) {
for (var E = t[T], S = [], _ = 0; _ < E.length; _++) {
var A = w(E[_]);
S.push(A)
}
return new y({
array: S
})
}
if ("tag" == T) {
var k = t[T];
if ("[object Array]" === Object.prototype.toString.call(k) && 3 == k.length) {
var C = w(k[2]);
return new b({
tag: k[0],
explicit: k[1],
obj: C
})
}
var D = {};
if (void 0 !== k.explicit && (D.explicit = k.explicit),
void 0 !== k.tag && (D.tag = k.tag),
void 0 === k.obj)
throw "obj shall be specified for 'tag'.";
return D.obj = w(k.obj),
new b(D)
}
}
,
this.jsonToASN1HEX = function(t) {
var e = this.newObject(t);
return e.getEncodedHex()
}
}
,
et.asn1.ASN1Util.oidHexToInt = function(t) {
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) {
var a = parseInt(t.substr(s, 2), 16)
, c = ("00000000" + a.toString(2)).slice(-8);
if (o += c.substr(1, 7),
"0" == c.substr(0, 1)) {
var u = new D(o,2);
e = e + "." + u.toString(10),
o = ""
}
}
return e
}
,
et.asn1.ASN1Util.oidIntToHex = function(t) {
var c = function(t) {
var e = t.toString(16);
return 1 == e.length && (e = "0" + e),
e
}
, e = function(t) {
var e = ""
, n = new D(t,10)
, r = n.toString(2)
, i = 7 - r.length % 7;
7 == i && (i = 0);
for (var o = "", s = 0; s < i; s++)
o += "0";
r = o + r;
for (var s = 0; s < r.length - 1; s += 7) {
var a = r.substr(s, 7);
s != r.length - 7 && (a = "1" + a),
e += c(parseInt(a, 2))
}
return e
};
if (!t.match(/^[0-9.]+$/))
throw "malformed oid string: " + t;
var n = ""
, r = t.split(".")
, i = 40 * parseInt(r[0]) + parseInt(r[1]);
n += c(i),
r.splice(0, 2);
for (var o = 0; o < r.length; o++)
n += e(r[o]);
return n
}
,
et.asn1.ASN1Object = function() {
this.getLengthHexFromValue = function() {
if (void 0 === this.hV || null == this.hV)
throw "this.hV is null or undefined.";
if (this.hV.length % 2 == 1)
throw "value hex must be even length: n=" + "".length + ",v=" + this.hV;
var t = this.hV.length / 2
, e = t.toString(16);
if (e.length % 2 == 1 && (e = "0" + e),
t < 128)
return e;
var n = e.length / 2;
if (15 < n)
throw "ASN.1 length too long to represent by 8x: n = " + t.toString(16);
var r = 128 + n;
return r.toString(16) + e
}
,
this.getEncodedHex = function() {
return null != this.hTLV && !this.isModified || (this.hV = this.getFreshValueHex(),
this.hL = this.getLengthHexFromValue(),
this.hTLV = this.hT + this.hL + this.hV,
this.isModified = !1),
this.hTLV
}
,
this.getValueHex = function() {
return this.getEncodedHex(),
this.hV
}
,
this.getFreshValueHex = function() {
return ""
}
}
,
et.asn1.DERAbstractString = function(t) {
et.asn1.DERAbstractString.superclass.constructor.call(this),
this.getString = function() {
return this.s
}
,
this.setString = function(t) {
this.hTLV = null,
this.isModified = !0,
this.s = t,
this.hV = stohex(this.s)
}
,
this.setStringHex = function(t) {
this.hTLV = null,
this.isModified = !0,
this.s = null,
this.hV = t
}
,
this.getFreshValueHex = function() {
return this.hV
}
,
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))
}
,
tt.lang.extend(et.asn1.DERAbstractString, et.asn1.ASN1Object),
et.asn1.DERAbstractTime = function(t) {
et.asn1.DERAbstractTime.superclass.constructor.call(this),
this.localDateToUTC = function(t) {
utc = t.getTime() + 6e4 * t.getTimezoneOffset();
var e = new Date(utc);
return e
}
,
this.formatDate = function(t, e, n) {
var r = this.zeroPadding
, i = this.localDateToUTC(t)
, o = String(i.getFullYear());
"utc" == e && (o = o.substr(2, 2));
var s = r(String(i.getMonth() + 1), 2)
, a = r(String(i.getDate()), 2)
, c = r(String(i.getHours()), 2)
, u = r(String(i.getMinutes()), 2)
, l = r(String(i.getSeconds()), 2)
, h = o + s + a + c + u + l;
if (!0 === n) {
var f = i.getMilliseconds();
if (0 != f) {
var d = r(String(f), 3);
d = d.replace(/[0]+$/, ""),
h = h + "." + d
}
}
return h + "Z"
}
,
this.zeroPadding = function(t, e) {
return t.length >= e ? t : new Array(e - t.length + 1).join("0") + t
}
,
this.getString = function() {
return this.s
}
,
this.setString = function(t) {
this.hTLV = null,
this.isModified = !0,
this.s = t,
this.hV = stohex(t)
}
,
this.setByDateValue = function(t, e, n, r, i, o) {
var s = new Date(Date.UTC(t, e - 1, n, r, i, o, 0));
this.setByDate(s)
}
,
this.getFreshValueHex = function() {
return this.hV
}
}
,
tt.lang.extend(et.asn1.DERAbstractTime, et.asn1.ASN1Object),
et.asn1.DERAbstractStructured = function(t) {
et.asn1.DERAbstractString.superclass.constructor.call(this),
this.setByASN1ObjectArray = function(t) {
this.hTLV = null,
this.isModified = !0,
this.asn1Array = t
}
,
this.appendASN1Object = function(t) {
this.hTLV = null,
this.isModified = !0,
this.asn1Array.push(t)
}
,
this.asn1Array = new Array,
void 0 !== t && void 0 !== t.array && (this.asn1Array = t.array)
}
,
tt.lang.extend(et.asn1.DERAbstractStructured, et.asn1.ASN1Object),
et.asn1.DERBoolean = function() {
et.asn1.DERBoolean.superclass.constructor.call(this),
this.hT = "01",
this.hTLV = "0101ff"
}
,
tt.lang.extend(et.asn1.DERBoolean, et.asn1.ASN1Object),
et.asn1.DERInteger = function(t) {
et.asn1.DERInteger.superclass.constructor.call(this),
this.hT = "02",
this.setByBigInteger = function(t) {
this.hTLV = null,
this.isModified = !0,
this.hV = et.asn1.ASN1Util.bigIntToMinTwosComplementsHex(t)
}
,
this.setByInteger = function(t) {
var e = new D(String(t),10);
this.setByBigInteger(e)
}
,
this.setValueHex = function(t) {
this.hV = t
}
,
this.getFreshValueHex = function() {
return this.hV
}
,
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))
}
,
tt.lang.extend(et.asn1.DERInteger, et.asn1.ASN1Object),
et.asn1.DERBitString = function(t) {
if (void 0 !== t && void 0 !== t.obj) {
var e = et.asn1.ASN1Util.newObject(t.obj);
t.hex = "00" + e.getEncodedHex()
}
et.asn1.DERBitString.superclass.constructor.call(this),
this.hT = "03",
this.setHexValueIncludingUnusedBits = function(t) {
this.hTLV = null,
this.isModified = !0,
this.hV = t
}
,
this.setUnusedBitsAndHexValue = function(t, e) {
if (t < 0 || 7 < t)
throw "unused bits shall be from 0 to 7: u = " + t;
var n = "0" + t;
this.hTLV = null,
this.isModified = !0,
this.hV = n + e
}
,
this.setByBinaryString = function(t) {
var e = 8 - (t = t.replace(/0+$/, "")).length % 8;
8 == e && (e = 0);
for (var n = 0; n <= e; n++)
t += "0";
for (var r = "", n = 0; n < t.length - 1; n += 8) {
var i = t.substr(n, 8)
, o = parseInt(i, 2).toString(16);
1 == o.length && (o = "0" + o),
r += o
}
this.hTLV = null,
this.isModified = !0,
this.hV = "0" + e + r
}
,
this.setByBooleanArray = function(t) {
for (var e = "", n = 0; n < t.length; n++)
1 == t[n] ? e += "1" : e += "0";
this.setByBinaryString(e)
}
,
this.newFalseArray = function(t) {
for (var e = new Array(t), n = 0; n < t; n++)
e[n] = !1;
return e
}
,
this.getFreshValueHex = function() {
return this.hV
}
,
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))
}
,
tt.lang.extend(et.asn1.DERBitString, et.asn1.ASN1Object),
et.asn1.DEROctetString = function(t) {
if (void 0 !== t && void 0 !== t.obj) {
var e = et.asn1.ASN1Util.newObject(t.obj);
t.hex = e.getEncodedHex()
}
et.asn1.DEROctetString.superclass.constructor.call(this, t),
this.hT = "04"
}
,
tt.lang.extend(et.asn1.DEROctetString, et.asn1.DERAbstractString),
et.asn1.DERNull = function() {
et.asn1.DERNull.superclass.constructor.call(this),
this.hT = "05",
this.hTLV = "0500"
}
,
tt.lang.extend(et.asn1.DERNull, et.asn1.ASN1Object),
et.asn1.DERObjectIdentifier = function(t) {
var c = function(t) {
var e = t.toString(16);
return 1 == e.length && (e = "0" + e),
e
}
, o = function(t) {
var e = ""
, n = new D(t,10)
, r = n.toString(2)
, i = 7 - r.length % 7;
7 == i && (i = 0);
for (var o = "", s = 0; s < i; s++)
o += "0";
r = o + r;
for (var s = 0; s < r.length - 1; s += 7) {
var a = r.substr(s, 7);
s != r.length - 7 && (a = "1" + a),
e += c(parseInt(a, 2))
}
return e
};
et.asn1.DERObjectIdentifier.superclass.constructor.call(this),
this.hT = "06",
this.setValueHex = function(t) {
this.hTLV = null,
this.isModified = !0,
this.s = null,
this.hV = t
}
,
this.setValueOidString = function(t) {
if (!t.match(/^[0-9.]+$/))
throw "malformed oid string: " + t;
var e = ""
, n = t.split(".")
, r = 40 * parseInt(n[0]) + parseInt(n[1]);
e += c(r),
n.splice(0, 2);
for (var i = 0; i < n.length; i++)
e += o(n[i]);
this.hTLV = null,
this.isModified = !0,
this.s = null,
this.hV = e
}
,
this.setValueName = function(t) {
var e = et.asn1.x509.OID.name2oid(t);
if ("" === e)
throw "DERObjectIdentifier oidName undefined: " + t;
this.setValueOidString(e)
}
,
this.getFreshValueHex = function() {
return this.hV
}
,
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))
}
,
tt.lang.extend(et.asn1.DERObjectIdentifier, et.asn1.ASN1Object),
et.asn1.DEREnumerated = function(t) {
et.asn1.DEREnumerated.superclass.constructor.call(this),
this.hT = "0a",
this.setByBigInteger = function(t) {
this.hTLV = null,
this.isModified = !0,
this.hV = et.asn1.ASN1Util.bigIntToMinTwosComplementsHex(t)
}
,
this.setByInteger = function(t) {
var e = new D(String(t),10);
this.setByBigInteger(e)
}
,
this.setValueHex = function(t) {
this.hV = t
}
,
this.getFreshValueHex = function() {
return this.hV
}
,
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))
}
,
tt.lang.extend(et.asn1.DEREnumerated, et.asn1.ASN1Object),
et.asn1.DERUTF8String = function(t) {
et.asn1.DERUTF8String.superclass.constructor.call(this, t),
this.hT = "0c"
}
,
tt.lang.extend(et.asn1.DERUTF8String, et.asn1.DERAbstractString),
et.asn1.DERNumericString = function(t) {
et.asn1.DERNumericString.superclass.constructor.call(this, t),
this.hT = "12"
}
,
tt.lang.extend(et.asn1.DERNumericString, et.asn1.DERAbstractString),
et.asn1.DERPrintableString = function(t) {
et.asn1.DERPrintableString.superclass.constructor.call(this, t),
this.hT = "13"
}
,
tt.lang.extend(et.asn1.DERPrintableString, et.asn1.DERAbstractString),
et.asn1.DERTeletexString = function(t) {
et.asn1.DERTeletexString.superclass.constructor.call(this, t),
this.hT = "14"
}
,
tt.lang.extend(et.asn1.DERTeletexString, et.asn1.DERAbstractString),
et.asn1.DERIA5String = function(t) {
et.asn1.DERIA5String.superclass.constructor.call(this, t),
this.hT = "16"
}
,
tt.lang.extend(et.asn1.DERIA5String, et.asn1.DERAbstractString),
et.asn1.DERUTCTime = function(t) {
et.asn1.DERUTCTime.superclass.constructor.call(this, t),
this.hT = "17",
this.setByDate = function(t) {
this.hTLV = null,
this.isModified = !0,
this.date = t,
this.s = this.formatDate(this.date, "utc"),
this.hV = stohex(this.s)
}
,
this.getFreshValueHex = function() {
return void 0 === this.date && void 0 === this.s && (this.date = new Date,
this.s = this.formatDate(this.date, "utc"),
this.hV = stohex(this.s)),
this.hV
}
,
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))
}
,
tt.lang.extend(et.asn1.DERUTCTime, et.asn1.DERAbstractTime),
et.asn1.DERGeneralizedTime = function(t) {
et.asn1.DERGeneralizedTime.superclass.constructor.call(this, t),
this.hT = "18",
this.withMillis = !1,
this.setByDate = function(t) {
this.hTLV = null,
this.isModified = !0,
this.date = t,
this.s = this.formatDate(this.date, "gen", this.withMillis),
this.hV = stohex(this.s)
}
,
this.getFreshValueHex = function() {
return void 0 === this.date && void 0 === this.s && (this.date = new Date,
this.s = this.formatDate(this.date, "gen", this.withMillis),
this.hV = stohex(this.s)),
this.hV
}
,
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),
!0 === t.millis && (this.withMillis = !0))
}
,
tt.lang.extend(et.asn1.DERGeneralizedTime, et.asn1.DERAbstractTime),
et.asn1.DERSequence = function(t) {
et.asn1.DERSequence.superclass.constructor.call(this, t),
this.hT = "30",
this.getFreshValueHex = function() {
for (var t = "", e = 0; e < this.asn1Array.length; e++) {
var n = this.asn1Array[e];
t += n.getEncodedHex()
}
return this.hV = t,
this.hV
}
}
,
tt.lang.extend(et.asn1.DERSequence, et.asn1.DERAbstractStructured),
et.asn1.DERSet = function(t) {
et.asn1.DERSet.superclass.constructor.call(this, t),
this.hT = "31",
this.sortFlag = !0,
this.getFreshValueHex = function() {
for (var t = new Array, e = 0; e < this.asn1Array.length; e++) {
var n = this.asn1Array[e];
t.push(n.getEncodedHex())
}
return 1 == this.sortFlag && t.sort(),
this.hV = t.join(""),
this.hV
}
,
void 0 !== t && void 0 !== t.sortflag && 0 == t.sortflag && (this.sortFlag = !1)
}
,
tt.lang.extend(et.asn1.DERSet, et.asn1.DERAbstractStructured),
et.asn1.DERTaggedObject = function(t) {
et.asn1.DERTaggedObject.superclass.constructor.call(this),
this.hT = "a0",
this.hV = "",
this.isExplicit = !0,
this.asn1Object = null,
this.setASN1Object = function(t, e, n) {
this.hT = e,
this.isExplicit = t,
this.asn1Object = n,
this.isExplicit ? (this.hV = this.asn1Object.getEncodedHex(),
this.hTLV = null,
this.isModified = !0) : (this.hV = null,
this.hTLV = n.getEncodedHex(),
this.hTLV = this.hTLV.replace(/^../, e),
this.isModified = !1)
}
,
this.getFreshValueHex = function() {
return this.hV
}
,
void 0 !== t && (void 0 !== t.tag && (this.hT = t.tag),
void 0 !== t.explicit && (this.isExplicit = t.explicit),
void 0 !== t.obj && (this.asn1Object = t.obj,
this.setASN1Object(this.isExplicit, this.hT, this.asn1Object)))
}
,
tt.lang.extend(et.asn1.DERTaggedObject, et.asn1.ASN1Object);
var nt = function(n) {
function r(t) {
var e = n.call(this) || this;
return t && ("string" == typeof t ? e.parseKey(t) : (r.hasPrivateKeyProperty(t) || r.hasPublicKeyProperty(t)) && e.parsePropertiesFrom(t)),
e
}
return function(t, e) {
function n() {
this.constructor = t
}
d(t, e),
t.prototype = null === e ? Object.create(e) : (n.prototype = e.prototype,
new n)
}(r, n),
r.prototype.parseKey = function(t) {
try {
var e = 0
, n = 0
, r = /^\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\s*)+$/.test(t) ? g.decode(t) : m.unarmor(t)
, i = _.decode(r);
if (3 === i.sub.length && (i = i.sub[2].sub[0]),
9 === i.sub.length) {
e = i.sub[1].getHexStringValue(),
this.n = j(e, 16),
n = i.sub[2].getHexStringValue(),
this.e = parseInt(n, 16);
var o = i.sub[3].getHexStringValue();
this.d = j(o, 16);
var s = i.sub[4].getHexStringValue();
this.p = j(s, 16);
var a = i.sub[5].getHexStringValue();
this.q = j(a, 16);
var c = i.sub[6].getHexStringValue();
this.dmp1 = j(c, 16);
var u = i.sub[7].getHexStringValue();
this.dmq1 = j(u, 16);
var l = i.sub[8].getHexStringValue();
this.coeff = j(l, 16)
} else {
if (2 !== i.sub.length)
return !1;
var h = i.sub[1]
, f = h.sub[0];
e = f.sub[0].getHexStringValue(),
this.n = j(e, 16),
n = f.sub[1].getHexStringValue(),
this.e = parseInt(n, 16)
}
return !0
} catch (t) {
return !1
}
}
,
r.prototype.getPrivateBaseKey = function() {
var t = {
array: [new et.asn1.DERInteger({
int: 0
}), new et.asn1.DERInteger({
bigint: this.n
}), new et.asn1.DERInteger({
int: this.e
}), new et.asn1.DERInteger({
bigint: this.d
}), new et.asn1.DERInteger({
bigint: this.p
}), new et.asn1.DERInteger({
bigint: this.q
}), new et.asn1.DERInteger({
bigint: this.dmp1
}), new et.asn1.DERInteger({
bigint: this.dmq1
}), new et.asn1.DERInteger({
bigint: this.coeff
})]
}
, e = new et.asn1.DERSequence(t);
return e.getEncodedHex()
}
,
r.prototype.getPrivateBaseKeyB64 = function() {
return l(this.getPrivateBaseKey())
}
,
r.prototype.getPublicBaseKey = function() {
var t = new et.asn1.DERSequence({
array: [new et.asn1.DERObjectIdentifier({
oid: "1.2.840.113549.1.1.1"
}), new et.asn1.DERNull]
})
, e = new et.asn1.DERSequence({
array: [new et.asn1.DERInteger({
bigint: this.n
}), new et.asn1.DERInteger({
int: this.e
})]
})
, n = new et.asn1.DERBitString({
hex: "00" + e.getEncodedHex()
})
, r = new et.asn1.DERSequence({
array: [t, n]
});
return r.getEncodedHex()
}
,
r.prototype.getPublicBaseKeyB64 = function() {
return l(this.getPublicBaseKey())
}
,
r.wordwrap = function(t, e) {
if (e = e || 64,
!t)
return t;
var n = "(.{1," + e + "})( +|$\n?)|(.{1," + e + "})";
return t.match(RegExp(n, "g")).join("\n")
}
,
r.prototype.getPrivateKey = function() {
var t = "-----BEGIN RSA PRIVATE KEY-----\n";
return t += r.wordwrap(this.getPrivateBaseKeyB64()) + "\n",
t += "-----END RSA PRIVATE KEY-----"
}
,
r.prototype.getPublicKey = function() {
var t = "-----BEGIN PUBLIC KEY-----\n";
return t += r.wordwrap(this.getPublicBaseKeyB64()) + "\n",
t += "-----END PUBLIC KEY-----"
}
,
r.hasPublicKeyProperty = function(t) {
return (t = t || {}).hasOwnProperty("n") && t.hasOwnProperty("e")
}
,
r.hasPrivateKeyProperty = function(t) {
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")
}
,
r.prototype.parsePropertiesFrom = function(t) {
this.n = t.n,
this.e = t.e,
t.hasOwnProperty("d") && (this.d = t.d,
this.p = t.p,
this.q = t.q,
this.dmp1 = t.dmp1,
this.dmq1 = t.dmq1,
this.coeff = t.coeff)
}
,
r
}(Z)
, rt = function() {
function t(t) {
t = t || {},
this.default_key_size = parseInt(t.default_key_size, 10) || 1024,
this.default_public_exponent = t.default_public_exponent || "010001",
this.log = t.log || !1,
this.key = null
}
return t.prototype.setKey = function(t) {
this.log && this.key,
this.key = new nt(t)
}
,
t.prototype.setPrivateKey = function(t) {
this.setKey(t)
}
,
t.prototype.setPublicKey = function(t) {
this.setKey(t)
}
,
t.prototype.decrypt = function(t) {
try {
return this.getKey().decrypt(h(t))
} catch (t) {
return !1
}
}
,
t.prototype.encrypt = function(t) {
try {
return l(this.getKey().encrypt(t))
} catch (t) {
return !1
}
}
,
t.prototype.sign = function(t, e, n) {
try {
return l(this.getKey().sign(t, e, n))
} catch (t) {
return !1
}
}
,
t.prototype.verify = function(t, e, n) {
try {
return this.getKey().verify(t, h(e), n)
} catch (t) {
return !1
}
}
,
t.prototype.getKey = function(t) {
if (!this.key) {
if (this.key = new nt,
t && "[object Function]" === {}.toString.call(t))
return void this.key.generateAsync(this.default_key_size, this.default_public_exponent, t);
this.key.generate(this.default_key_size, this.default_public_exponent)
}
return this.key
}
,
t.prototype.getPrivateKey = function() {
return this.getKey().getPrivateKey()
}
,
t.prototype.getPrivateKeyB64 = function() {
return this.getKey().getPrivateBaseKeyB64()
}
,
t.prototype.getPublicKey = function() {
return this.getKey().getPublicKey()
}
,
t.prototype.getPublicKeyB64 = function() {
return this.getKey().getPublicBaseKeyB64()
}
,
t.version = "3.0.0-rc.1",
t
}();
window.JSEncrypt = rt,
t.JSEncrypt = rt,
t.default = rt,
Object.defineProperty(t, "__esModule", {
value: !0
})
}(e)
},
19:function(F, K, W) {
var z;
!function(i, h) {
"use strict";
function t(t) {
for (var e = {}, n = 0; n < t.length; n++)
e[t[n].toUpperCase()] = t[n];
return e
}
function o(t, e) {
return typeof t == u && -1 !== L(e).indexOf(L(t))
}
function s(t, e) {
if (typeof t == u)
return t = t.replace(/^\s\s*/, "").replace(/\s\s*$/, ""),
typeof e == c ? t : t.substring(0, 255)
}
function a(t, e) {
for (var n, r, i, o, s, a, c = 0; c < e.length && !s; ) {
var u = e[c]
, l = e[c + 1];
for (n = r = 0; n < u.length && !s; )
if (s = u[n++].exec(t))
for (i = 0; i < l.length; i++)
a = s[++r],
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;
c += 2
}
}
function e(t, e) {
for (var n in e)
if (typeof e[n] == d && 0 < e[n].length) {
for (var r = 0; r < e[n].length; r++)
if (o(e[n][r], t))
return "?" === n ? h : n
} else if (o(e[n], t))
return "?" === n ? h : n;
return t
}
var f = "function"
, c = "undefined"
, d = "object"
, u = "string"
, l = "model"
, p = "name"
, g = "type"
, m = "vendor"
, v = "version"
, y = "architecture"
, n = "console"
, r = "mobile"
, b = "tablet"
, w = "smarttv"
, x = "wearable"
, T = "embedded"
, E = "Amazon"
, S = "Apple"
, _ = "BlackBerry"
, A = "Browser"
, k = "Chrome"
, C = "Firefox"
, D = "Google"
, N = "Microsoft"
, O = "Motorola"
, R = "Opera"
, I = "Samsung"
, P = "Sony"
, j = "Zebra"
, B = "Facebook"
, L = function(t) {
return t.toLowerCase()
}
, M = {
ME: "4.90",
"NT 3.11": "NT3.51",
"NT 4.0": "NT4.0",
2e3: "NT 5.0",
XP: ["NT 5.1", "NT 5.2"],
Vista: "NT 6.0",
7: "NT 6.1",
8: "NT 6.2",
8.1: "NT 6.3",
10: ["NT 6.4", "NT 10.0"],
RT: "ARM"
}
, V = {
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, {
"1.0": "/8",
1.2: "/1",
1.3: "/3",
"2.0": "/412",
"2.0.2": "/416",
"2.0.3": "/417",
"2.0.4": "/419",
"?": "/"
}]], [/(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]],
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]]],
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"]]],
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]],
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]]
}
, q = function(t, e) {
if (typeof t == d && (e = t,
t = h),
!(this instanceof q))
return new q(t,e).getResult();
var n = t || (typeof i != c && i.navigator && i.navigator.userAgent ? i.navigator.userAgent : "")
, r = e ? function(t, e) {
var n = {};
for (var r in t)
e[r] && e[r].length % 2 == 0 ? n[r] = e[r].concat(t[r]) : n[r] = t[r];
return n
}(V, e) : V;
return this.getBrowser = function() {
var t = {};
return t[p] = h,
t[v] = h,
a.call(t, n, r.browser),
t.major = function(t) {
return typeof t == u ? t.replace(/[^\d\.]/g, "").split(".")[0] : h
}(t.version),
t
}
,
this.getCPU = function() {
var t = {};
return t[y] = h,
a.call(t, n, r.cpu),
t
}
,
this.getDevice = function() {
var t = {};
return t[m] = h,
t[l] = h,
t[g] = h,
a.call(t, n, r.device),
t
}
,
this.getEngine = function() {
var t = {};
return t[p] = h,
t[v] = h,
a.call(t, n, r.engine),
t
}
,
this.getOS = function() {
var t = {};
return t[p] = h,
t[v] = h,
a.call(t, n, r.os),
t
}
,
this.getResult = function() {
return {
ua: this.getUA(),
browser: this.getBrowser(),
engine: this.getEngine(),
os: this.getOS(),
device: this.getDevice(),
cpu: this.getCPU()
}
}
,
this.getUA = function() {
return n
}
,
this.setUA = function(t) {
return n = typeof t == u && 255 < t.length ? s(t, 255) : t,
this
}
,
this.setUA(n),
this
};
q.VERSION = "1.0.2",
q.BROWSER = t([p, v, "major"]),
q.CPU = t([y]),
q.DEVICE = t([l, m, g, n, r, w, b, x, T]),
q.ENGINE = q.OS = t([p, v]),
typeof K != c ? (typeof F != c && F.exports && (K = F.exports = q),
K.UAParser = q) : W(51) ? (z = function() {
return q
}
.call(K, W, K, F)) === h || (F.exports = z) : typeof i != c && (i.UAParser = q);
var U = typeof i != c && (i.jQuery || i.Zepto);
if (U && !U.ua) {
var H = new q;
U.ua = H.getResult(),
U.ua.get = function() {
return H.getUA()
}
,
U.ua.set = function(t) {
H.setUA(t);
var e = H.getResult();
for (var n in e)
U.ua[n] = e[n]
}
}
}("object" == typeof window ? window : this)
},
2: function(t, e, n) {
"use strict";
n.r(e),
n.d(e, "makeParam", function() {
return o
}),
n.d(e, "sendFee", function() {
return r
});
var o = function(e) {
var n = "";
try {
n = JSON.stringify(e.detail)
} catch (t) {
n = Object.prototype.toString.call(e.detail)
}
return {
type: "error",
common: {
pid: e.pid,
uuid: e.uuid,
ucid: e.ucid,
is_test: "test" === e.env,
record: {
time_on_page: !0,
performance: !0,
js_error: !0,
js_error_report_config: {
ERROR_RUNTIME: !0,
ERROR_SCRIPT: !0,
ERROR_STYLE: !0,
ERROR_IMAGE: !0,
ERROR_AUDIO: !0,
ERROR_VIDEO: !0,
ERROR_CONSOLE: !0,
ERROR_TRY_CATCH: !0
}
},
version: "1.0.0",
timestamp: Date.now(),
runtime_version: e.version,
sdk_version: "1.3.0",
page_type: e.pageUrl || "/"
},
code: 8,
extra: {
desc: n
},
detail: {
error_no: e.errorName || "unknown_error",
url: e.pageUrl || "",
http_code: 0,
during_ms: 0,
request_size_b: 0,
response_size_b: 0
}
}
}
, r = function(t) {
var e = t.errorName
, n = t.detail
, r = o({
detail: n,
env: /test/.test(window.location.href) ? "test" : "prod",
errorName: e,
pid: "pc_login_sdk",
ucid: 1,
uuid: "",
version: "1.2.0"
})
, i = "https://dig.lianjia.com/fee.gif?d=" + encodeURIComponent(JSON.stringify(r));
try {
new Image(0,0).src = i
} catch (t) {}
}
},
0: function(t, e, n) {
"use strict";
n.r(e),
n.d(e, "scene", function() {
return L
}),
n.d(e, "withCredentialDomain", function() {
return M
}),
n.d(e, "APIEndpoint", function() {
return r
}),
n.d(e, "PasswordAPIEndpoint", function() {
return o
}),
n.d(e, "captchaDomain", function() {
return a
}),
n.d(e, "captchaJSAddr", function() {
return u
}),
n.d(e, "APIDomainKe", function() {
return h
}),
n.d(e, "APIDomainDeyoulife", function() {
return d
}),
n.d(e, "APIDomainLianjia", function() {
return g
}),
n.d(e, "mainAuthMethodName", function() {
return v
}),
n.d(e, "TitleEnum", function() {
return b
}),
n.d(e, "allianceMethods", function() {
return x
}),
n.d(e, "SupportedIdentityCheckMethodsEnum", function() {
return E
}),
n.d(e, "accountSystem", function() {
return _
}),
n.d(e, "smsTypeEnum", function() {
return k
}),
n.d(e, "SceneKey", function() {
return D
}),
n.d(e, "AuthStatus", function() {
return O
}),
n.d(e, "Gender", function() {
return I
}),
n.d(e, "Views", function() {
return j
});
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) {
return String.fromCharCode(Number(t))
}).reduce(function(t, e) {
return t + e
}), M = ["ke.com", "lianjia.com", "deyoulife.com"];
(i = r = r || {}).init = "/authentication/initialize",
i.auth = "/authentication/authenticate",
i.sms = "/authentication/mfa/sms",
i.getinfo = "/serviceValidate",
i.register = "/registration/register",
i.logout = "/authentication/destroy",
i.userLogout = "/logout",
i.qr = "/qrcode",
i.polling = "/qrcode/status",
(s = o = o || {}).init = "/authentication/password/initialize",
s.change = "/authentication/password",
s.reset = "/authentication/reset-password",
s.validate = "/authentication/password/action/validate",
(c = a = a || {}).dev = "//test3-captcha.lianjia.com",
c.test = "//test3-captcha.lianjia.com",
c.prod = "https://captcha.lianjia.com",
c.preview = "https://captcha.lianjia.com",
(l = u = u || {}).dev = "//test-s1.ljcdn.com/test-captcha-js-sdk-v2/captcha.js",
l.test = "//test-s1.ljcdn.com/test-captcha-js-sdk-v2/captcha.js",
l.prod = "https://s1.ljcdn.com/captcha-js-sdk-v2/captcha.js",
l.preview = "https://s1.ljcdn.com/captcha-js-sdk-v2/captcha.js",
(f = h = h || {}).dev = "http://alps-passport.login-dev.tta.test.ke.com",
f.test = "https://test-clogin.ke.com",
f.prod = "https://clogin.ke.com",
f.preview = "https://clogin.ke.com",
(p = d = d || {}).dev = "http://alps-passport.login-dev.tta.test.ke.com",
p.test = "https://test-clogin.ke.com",
p.prod = "https://clogin.ke.com",
p.preview = "https://clogin.ke.com",
(m = g = g || {}).dev = "http://alps-passport.login-dev.tta.test.ke.com",
m.test = "https://test-clogin.lianjia.com",
m.prod = "https://clogin.lianjia.com",
m.preview = "https://clogin.lianjia.com",
(y = v = v || {}).PASSWORD = "username-password",
y.QR = "qrcode",
y.PHONE = "phone-code",
(w = b = b || {})["username-password"] = "账号密码登录",
w.qrcode = "二维码登录",
w["phone-code"] = "短信验证码登录",
(T = x = x || {}).security = "security-code",
T.shield = "shield-code",
(S = E = E || {}).id_num = "id-num",
S.security_code = "security-code",
S.old_password = "old-password",
S.security_code_id_num = "security-code&id-num",
(A = _ = _ || {}).commerceSeller = "commerce-seller",
A.customer = "customer",
A.employee = "employee",
A.guangsha = "guangsha",
A.rentSaas = "rent-saas",
(C = k = k || {}).sms = "sms",
C.voice = "voice",
(N = D = D || {}).DEFAULT = "DEFAULT",
N.WHEN_LOGIN = "WHEN_LOGIN",
N.WHEN_VALIDATE_PASSWORD = "WHEN_VALIDATE_PASSWORD",
N.WHEN_REGISTER = "WHEN_REGISTER",
N.WHEN_RESET_PASSWORD = "WHEN_RESET_PASSWORD",
N.WHEN_LOGOUT = "WHEN_LOGOUT",
N.WHEN_SEND_SMS = "WHEN_SEND_SMS",
N.WHEN_RESET_PASSWORD_SEND_SMS = "WHEN_RESET_PASSWORD_SEND_SMS",
(R = O = O || {}).PASS = "PASS",
R.WARN = "WARN",
(P = I = I || {}).MALE = "MALE",
P.FEMALE = "FEMALE",
(B = j = j || {})[B.passwordlogin = 0] = "passwordlogin",
B[B.smslogin = 1] = "smslogin",
B[B.resetpassword = 2] = "resetpassword",
B[B.register = 3] = "register",
e.default = {
scene: L,
APIEndpoint: r,
PasswordAPIEndpoint: o,
captchaDomain: a,
captchaJSAddr: u,
mainAuthMethodName: v,
TitleEnum: b,
allianceMethods: x,
accountSystem: _,
Gender: I,
SceneKey: D,
AuthStatus: O,
APIDomainKe: h,
APIDomainLianjia: g,
Views: j
}
},
1:function(t, e, n) {
"use strict";
n.r(e),
n.d(e, "loadScriptWithPromise", function() {
return f
}),
n.d(e, "commonValidator", function() {
return d
}),
n.d(e, "triggerInput", function() {
return p
}),
n.d(e, "maskPhoneNumber", function() {
return g
}),
n.d(e, "ulog", function() {
return m
}),
n.d(e, "fetch", function() {
return v
}),
n.d(e, "Xml2Json", function() {
return y
}),
n.d(e, "parseUserInfo", function() {
return b
}),
n.d(e, "cookie", function() {
return w
}),
n.d(e, "getEnv", function() {
return x
}),
n.d(e, "parseURL", function() {
return T
}),
n.d(e, "env", function() {
return E
}),
n.d(e, "plat", function() {
return S
}),
n.d(e, "withCredential", function() {
return _
}),
n.d(e, "getQuery", function() {
return A
});
var r = n(7)
, o = n.n(r)
, i = n(4)
, a = n.n(i);
a.a.defaults.withCredentials = !0;
function s(t) {
var e = document.createElement("b");
return e.innerHTML = "\x3c!--[if IE " + t + "]>>> 24) | 4278255360 & (n[c] << 24 | n[c] >>> 8);
n[r >>> 5] |= 128 << r % 32,
n[14 + (64 + r >>> 9 << 4)] = r;
var u = x._ff
, l = x._gg
, h = x._hh
, f = x._ii;
for (c = 0; c < n.length; c += 16) {
var d = i
, p = o
, g = s
, m = a;
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),
i = i + d >>> 0,
o = o + p >>> 0,
s = s + g >>> 0,
a = a + m >>> 0
}
return v.endian([i, o, s, a])
}
)._ff = function(t, e, n, r, i, o, s) {
var a = t + (e & n | ~e & r) + (i >>> 0) + s;
return (a << o | a >>> 32 - o) + e
}
,
x._gg = function(t, e, n, r, i, o, s) {
var a = t + (e & r | n & ~r) + (i >>> 0) + s;
return (a << o | a >>> 32 - o) + e
}
,
x._hh = function(t, e, n, r, i, o, s) {
var a = t + (e ^ n ^ r) + (i >>> 0) + s;
return (a << o | a >>> 32 - o) + e
}
,
x._ii = function(t, e, n, r, i, o, s) {
var a = t + (n ^ (e | ~r)) + (i >>> 0) + s;
return (a << o | a >>> 32 - o) + e
}
,
x._blocksize = 16,
x._digestsize = 16,
t.exports = function(t, e) {
if (null == t)
throw new Error("Illegal argument " + t);
var n = v.wordsToBytes(x(t, e));
return e && e.asBytes ? n : e && e.asString ? w.bytesToString(n) : v.bytesToHex(n)
}
},
30:function(t, e) {
var o, n;
o = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
n = {
rotl: function(t, e) {
return t << e | t >>> 32 - e
},
rotr: function(t, e) {
return t << 32 - e | t >>> e
},
endian: function(t) {
if (t.constructor == Number)
return 16711935 & n.rotl(t, 8) | 4278255360 & n.rotl(t, 24);
for (var e = 0; e < t.length; e++)
t[e] = n.endian(t[e]);
return t
},
randomBytes: function(t) {
for (var e = []; 0 < t; t--)
e.push(Math.floor(256 * Math.random()));
return e
},
bytesToWords: function(t) {
for (var e = [], n = 0, r = 0; n < t.length; n++,
r += 8)
e[r >>> 5] |= t[n] << 24 - r % 32;
return e
},
wordsToBytes: function(t) {
for (var e = [], n = 0; n < 32 * t.length; n += 8)
e.push(t[n >>> 5] >>> 24 - n % 32 & 255);
return e
},
bytesToHex: function(t) {
for (var e = [], n = 0; n < t.length; n++)
e.push((t[n] >>> 4).toString(16)),
e.push((15 & t[n]).toString(16));
return e.join("")
},
hexToBytes: function(t) {
for (var e = [], n = 0; n < t.length; n += 2)
e.push(parseInt(t.substr(n, 2), 16));
return e
},
bytesToBase64: function(t) {
for (var e = [], n = 0; n < t.length; n += 3)
for (var r = t[n] << 16 | t[n + 1] << 8 | t[n + 2], i = 0; i < 4; i++)
8 * n + 6 * i <= 8 * t.length ? e.push(o.charAt(r >>> 6 * (3 - i) & 63)) : e.push("=");
return e.join("")
},
base64ToBytes: function(t) {
t = t.replace(/[^A-Z0-9+\/]/gi, "");
for (var e = [], n = 0, r = 0; n < t.length; r = ++n % 4)
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);
return e
}
},
t.exports = n
},
10: function(t, e) {
var n = {
utf8: {
stringToBytes: function(t) {
return n.bin.stringToBytes(unescape(encodeURIComponent(t)))
},
bytesToString: function(t) {
return decodeURIComponent(escape(n.bin.bytesToString(t)))
}
},
bin: {
stringToBytes: function(t) {
for (var e = [], n = 0; n < t.length; n++)
e.push(255 & t.charCodeAt(n));
return e
},
bytesToString: function(t) {
for (var e = [], n = 0; n < t.length; n++)
e.push(String.fromCharCode(t[n]));
return e.join("")
}
}
};
t.exports = n
},
31:function(t, e) {
function n(t) {
return !!t.constructor && "function" == typeof t.constructor.isBuffer && t.constructor.isBuffer(t)
}
t.exports = function(t) {
return null != t && (n(t) || function(t) {
return "function" == typeof t.readFloatLE && "function" == typeof t.slice && n(t.slice(0, 0))
}(t) || !!t._isBuffer)
}
},
4:function(t, e, n) {
t.exports = n(32)
},
32: function(t, e, n) {
"use strict";
var r = n(3)
, i = n(11)
, o = n(34)
, s = n(17);
function a(t) {
var e = new o(t)
, n = i(o.prototype.request, e);
return r.extend(n, o.prototype, e),
r.extend(n, e),
n
}
var c = a(n(14));
c.Axios = o,
c.create = function(t) {
return a(s(c.defaults, t))
}
,
c.Cancel = n(18),
c.CancelToken = n(47),
c.isCancel = n(13),
c.all = function(t) {
return Promise.all(t)
}
,
c.spread = n(48),
t.exports = c,
t.exports.default = c
},
3:function(t, e, n) {
"use strict";
var i = n(11)
, r = n(33)
, o = Object.prototype.toString;
function s(t) {
return "[object Array]" === o.call(t)
}
function a(t) {
return null !== t && "object" == typeof t
}
function c(t) {
return "[object Function]" === o.call(t)
}
function u(t, e) {
if (null != t)
if ("object" != typeof t && (t = [t]),
s(t))
for (var n = 0, r = t.length; n < r; n++)
e.call(null, t[n], n, t);
else
for (var i in t)
Object.prototype.hasOwnProperty.call(t, i) && e.call(null, t[i], i, t)
}
t.exports = {
isArray: s,
isArrayBuffer: function(t) {
return "[object ArrayBuffer]" === o.call(t)
},
isBuffer: r,
isFormData: function(t) {
return "undefined" != typeof FormData && t instanceof FormData
},
isArrayBufferView: function(t) {
return "undefined" != typeof ArrayBuffer && ArrayBuffer.isView ? ArrayBuffer.isView(t) : t && t.buffer && t.buffer instanceof ArrayBuffer
},
isString: function(t) {
return "string" == typeof t
},
isNumber: function(t) {
return "number" == typeof t
},
isObject: a,
isUndefined: function(t) {
return void 0 === t
},
isDate: function(t) {
return "[object Date]" === o.call(t)
},
isFile: function(t) {
return "[object File]" === o.call(t)
},
isBlob: function(t) {
return "[object Blob]" === o.call(t)
},
isFunction: c,
isStream: function(t) {
return a(t) && c(t.pipe)
},
isURLSearchParams: function(t) {
return "undefined" != typeof URLSearchParams && t instanceof URLSearchParams
},
isStandardBrowserEnv: function() {
return ("undefined" == typeof navigator || "ReactNative" !== navigator.product && "NativeScript" !== navigator.product && "NS" !== navigator.product) && ("undefined" != typeof window && "undefined" != typeof document)
},
forEach: u,
merge: function n() {
var r = {};
function t(t, e) {
"object" == typeof r[e] && "object" == typeof t ? r[e] = n(r[e], t) : r[e] = t
}
for (var e = 0, i = arguments.length; e < i; e++)
u(arguments[e], t);
return r
},
deepMerge: function n() {
var r = {};
function t(t, e) {
"object" == typeof r[e] && "object" == typeof t ? r[e] = n(r[e], t) : r[e] = "object" == typeof t ? n({}, t) : t
}
for (var e = 0, i = arguments.length; e < i; e++)
u(arguments[e], t);
return r
},
extend: function(n, t, r) {
return u(t, function(t, e) {
n[e] = r && "function" == typeof t ? i(t, r) : t
}),
n
},
trim: function(t) {
return t.replace(/^\s*/, "").replace(/\s*$/, "")
}
}
},
11:function(t, e, n) {
"use strict";
t.exports = function(n, r) {
return function() {
for (var t = new Array(arguments.length), e = 0; e < t.length; e++)
t[e] = arguments[e];
return n.apply(r, t)
}
}
},
33:function (t, e) {
t.exports = function(t) {
return null != t && null != t.constructor && "function" == typeof t.constructor.isBuffer && t.constructor.isBuffer(t)
}
},
34: function(t, e, n) {
"use strict";
var i = n(3)
, r = n(12)
, o = n(35)
, s = n(36)
, a = n(17);
function c(t) {
this.defaults = t,
this.interceptors = {
request: new o,
response: new o
}
}
c.prototype.request = function(t, e) {
"string" == typeof t ? (t = e || {}).url = arguments[0] : t = t || {},
(t = a(this.defaults, t)).method = t.method ? t.method.toLowerCase() : "get";
var n = [s, void 0]
, r = Promise.resolve(t);
for (this.interceptors.request.forEach(function(t) {
n.unshift(t.fulfilled, t.rejected)
}),
this.interceptors.response.forEach(function(t) {
n.push(t.fulfilled, t.rejected)
}); n.length; )
r = r.then(n.shift(), n.shift());
return r
}
,
c.prototype.getUri = function(t) {
return t = a(this.defaults, t),
r(t.url, t.params, t.paramsSerializer).replace(/^\?/, "")
}
,
i.forEach(["delete", "get", "head", "options"], function(n) {
c.prototype[n] = function(t, e) {
return this.request(i.merge(e || {}, {
method: n,
url: t
}))
}
}),
i.forEach(["post", "put", "patch"], function(r) {
c.prototype[r] = function(t, e, n) {
return this.request(i.merge(n || {}, {
method: r,
url: t,
data: e
}))
}
}),
t.exports = c
},
12: function(t, e, n) {
"use strict";
var s = n(3);
function a(t) {
return encodeURIComponent(t).replace(/%40/gi, "@").replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+").replace(/%5B/gi, "[").replace(/%5D/gi, "]")
}
t.exports = function(t, e, n) {
if (!e)
return t;
var r;
if (n)
r = n(e);
else if (s.isURLSearchParams(e))
r = e.toString();
else {
var i = [];
s.forEach(e, function(t, e) {
null != t && (s.isArray(t) ? e += "[]" : t = [t],
s.forEach(t, function(t) {
s.isDate(t) ? t = t.toISOString() : s.isObject(t) && (t = JSON.stringify(t)),
i.push(a(e) + "=" + a(t))
}))
}),
r = i.join("&")
}
if (r) {
var o = t.indexOf("#");
-1 !== o && (t = t.slice(0, o)),
t += (-1 === t.indexOf("?") ? "?" : "&") + r
}
return t
}
},
35:function(t, e, n) {
"use strict";
var r = n(3);
function i() {
this.handlers = []
}
i.prototype.use = function(t, e) {
return this.handlers.push({
fulfilled: t,
rejected: e
}),
this.handlers.length - 1
}
,
i.prototype.eject = function(t) {
this.handlers[t] && (this.handlers[t] = null)
}
,
i.prototype.forEach = function(e) {
r.forEach(this.handlers, function(t) {
null !== t && e(t)
})
}
,
t.exports = i
},
36:function(t, e, n) {
"use strict";
var r = n(3)
, i = n(37)
, o = n(13)
, s = n(14)
, a = n(45)
, c = n(46);
function u(t) {
t.cancelToken && t.cancelToken.throwIfRequested()
}
t.exports = function(e) {
return u(e),
e.baseURL && !a(e.url) && (e.url = c(e.baseURL, e.url)),
e.headers = e.headers || {},
e.data = i(e.data, e.headers, e.transformRequest),
e.headers = r.merge(e.headers.common || {}, e.headers[e.method] || {}, e.headers || {}),
r.forEach(["delete", "get", "head", "post", "put", "patch", "common"], function(t) {
delete e.headers[t]
}),
(e.adapter || s.adapter)(e).then(function(t) {
return u(e),
t.data = i(t.data, t.headers, e.transformResponse),
t
}, function(t) {
return o(t) || (u(e),
t && t.response && (t.response.data = i(t.response.data, t.response.headers, e.transformResponse))),
Promise.reject(t)
})
}
},
37 : function(t, e, n) {
"use strict";
var r = n(3);
t.exports = function(e, n, t) {
return r.forEach(t, function(t) {
e = t(e, n)
}),
e
}
},
38: function(t, e) {
var n, r, i = t.exports = {};
function o() {
throw new Error("setTimeout has not been defined")
}
function s() {
throw new Error("clearTimeout has not been defined")
}
function a(e) {
if (n === setTimeout)
return setTimeout(e, 0);
if ((n === o || !n) && setTimeout)
return n = setTimeout,
setTimeout(e, 0);
try {
return n(e, 0)
} catch (t) {
try {
return n.call(null, e, 0)
} catch (t) {
return n.call(this, e, 0)
}
}
}
!function() {
try {
n = "function" == typeof setTimeout ? setTimeout : o
} catch (t) {
n = o
}
try {
r = "function" == typeof clearTimeout ? clearTimeout : s
} catch (t) {
r = s
}
}();
var c, u = [], l = !1, h = -1;
function f() {
l && c && (l = !1,
c.length ? u = c.concat(u) : h = -1,
u.length && d())
}
function d() {
if (!l) {
var t = a(f);
l = !0;
for (var e = u.length; e; ) {
for (c = u,
u = []; ++h < e; )
c && c[h].run();
h = -1,
e = u.length
}
c = null,
l = !1,
function(e) {
if (r === clearTimeout)
return clearTimeout(e);
if ((r === s || !r) && clearTimeout)
return r = clearTimeout,
clearTimeout(e);
try {
r(e)
} catch (t) {
try {
return r.call(null, e)
} catch (t) {
return r.call(this, e)
}
}
}(t)
}
}
function p(t, e) {
this.fun = t,
this.array = e
}
function g() {}
i.nextTick = function(t) {
var e = new Array(arguments.length - 1);
if (1 < arguments.length)
for (var n = 1; n < arguments.length; n++)
e[n - 1] = arguments[n];
u.push(new p(t,e)),
1 !== u.length || l || a(d)
}
,
p.prototype.run = function() {
this.fun.apply(null, this.array)
}
,
i.title = "browser",
i.browser = !0,
i.env = {},
i.argv = [],
i.version = "",
i.versions = {},
i.on = g,
i.addListener = g,
i.once = g,
i.off = g,
i.removeListener = g,
i.removeAllListeners = g,
i.emit = g,
i.prependListener = g,
i.prependOnceListener = g,
i.listeners = function(t) {
return []
}
,
i.binding = function(t) {
throw new Error("process.binding is not supported")
}
,
i.cwd = function() {
return "/"
}
,
i.chdir = function(t) {
throw new Error("process.chdir is not supported")
}
,
i.umask = function() {
return 0
}
},
39: function(t, e, n) {
"use strict";
var i = n(3);
t.exports = function(n, r) {
i.forEach(n, function(t, e) {
e !== r && e.toUpperCase() === r.toUpperCase() && (n[r] = t,
delete n[e])
})
}
},
13: function(t, e, n) {
"use strict";
t.exports = function(t) {
return !(!t || !t.__CANCEL__)
}
},
14:function(a, t, c) {
"use strict";
(function(t) {
var n = c(3)
, r = c(39)
, e = {
"Content-Type": "application/x-www-form-urlencoded"
};
function i(t, e) {
!n.isUndefined(t) && n.isUndefined(t["Content-Type"]) && (t["Content-Type"] = e)
}
var o, s = {
adapter: (void 0 !== t && "[object process]" === Object.prototype.toString.call(t) ? o = c(15) : "undefined" != typeof XMLHttpRequest && (o = c(15)),
o),
transformRequest: [function(t, e) {
return r(e, "Accept"),
r(e, "Content-Type"),
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"),
t.toString()) : n.isObject(t) ? (i(e, "application/json;charset=utf-8"),
JSON.stringify(t)) : t
}
],
transformResponse: [function(t) {
if ("string" == typeof t)
try {
t = JSON.parse(t)
} catch (t) {}
return t
}
],
timeout: 0,
xsrfCookieName: "XSRF-TOKEN",
xsrfHeaderName: "X-XSRF-TOKEN",
maxContentLength: -1,
validateStatus: function(t) {
return 200 <= t && t < 300
}
};
s.headers = {
common: {
Accept: "application/json, text/plain, */*"
}
},
n.forEach(["delete", "get", "head"], function(t) {
s.headers[t] = {}
}),
n.forEach(["post", "put", "patch"], function(t) {
s.headers[t] = n.merge(e)
}),
a.exports = s
}
).call(this, c(38))
},
45:function(t, e, n) {
"use strict";
t.exports = function(t) {
return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(t)
}
}
,46:function(t, e, n) {
"use strict";
t.exports = function(t, e) {
return e ? t.replace(/\/+$/, "") + "/" + e.replace(/^\/+/, "") : t
}
}
, 47:function(t, e, n) {
"use strict";
var r = n(18);
function i(t) {
if ("function" != typeof t)
throw new TypeError("executor must be a function.");
var e;
this.promise = new Promise(function(t) {
e = t
}
);
var n = this;
t(function(t) {
n.reason || (n.reason = new r(t),
e(n.reason))
})
}
i.prototype.throwIfRequested = function() {
if (this.reason)
throw this.reason
}
,
i.source = function() {
var e;
return {
token: new i(function(t) {
e = t
}
),
cancel: e
}
}
,
t.exports = i
}
, 48:function(t, e, n) {
"use strict";
t.exports = function(e) {
return function(t) {
return e.apply(null, t)
}
}
},
17:function(t, e, n) {
"use strict";
var i = n(3);
t.exports = function(e, n) {
n = n || {};
var r = {};
return i.forEach(["url", "method", "params", "data"], function(t) {
void 0 !== n[t] && (r[t] = n[t])
}),
i.forEach(["headers", "auth", "proxy"], function(t) {
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])
}),
i.forEach(["baseURL", "transformRequest", "transformResponse", "paramsSerializer", "timeout", "withCredentials", "adapter", "responseType", "xsrfCookieName", "xsrfHeaderName", "onUploadProgress", "onDownloadProgress", "maxContentLength", "validateStatus", "maxRedirects", "httpAgent", "httpsAgent", "cancelToken", "socketPath"], function(t) {
void 0 !== n[t] ? r[t] = n[t] : void 0 !== e[t] && (r[t] = e[t])
}),
r
}
},
18:function(t, e, n) {
"use strict";
function r(t) {
this.message = t
}
r.prototype.toString = function() {
return "Cancel" + (this.message ? ": " + this.message : "")
}
,
r.prototype.__CANCEL__ = !0,
t.exports = r
},
}
);
function get_passwrod(phone){
aaa(50).default()
var e = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJxBJn2gY+D2OdldUxpsNwIGyKc/QRvqbWWGIdIewE7SxyyGHNcLdT+2bb6E6Ko7jBlEElUBkKJJ93G761dp6pXu7ORTjJ1mta99Bjud7+u/3473mG+QReoH4ux8idsd+E0TW0HWUP6zyfYy42HPSaN3pjetM30sVazdWxpvAH6wIDAQAB";
ddd.ec.setPublicKey(e);
ddd.publicKey = e;
console.log(ddd.ec.encrypt(phone));
return ddd.ec.encrypt(phone)
}
================================================
FILE: 第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例三.js
================================================
/*!
爬虫逆向进阶实战-JS逆向3.4.1 webpack案例三
视频地址:https://www.bilibili.com/video/bv1MB4y1h7nK
*/
var aaa;
!function(g) {
"use strict";
var r, e, t, i;
r = {
1: [function(t, i, n) {
i.exports = function(t, i) {
var n = Array(arguments.length - 1)
, s = 0
, r = 2
, u = !0;
for (; r < arguments.length; )
n[s++] = arguments[r++];
return new Promise(function(r, e) {
n[s] = function(t) {
if (u)
if (u = !1,
t)
e(t);
else {
for (var i = Array(arguments.length - 1), n = 0; n < i.length; )
i[n++] = arguments[n];
r.apply(null, i)
}
}
;
try {
t.apply(i || null, n)
} catch (t) {
u && (u = !1,
e(t))
}
}
)
}
}
, {}],
2: [function(t, i, n) {
n.length = function(t) {
var i = t.length;
if (!i)
return 0;
for (var n = 0; 1 < --i % 4 && "=" == (t[0 | i] || ""); )
++n;
return Math.ceil(3 * t.length) / 4 - n
}
;
for (var f = Array(64), h = Array(123), r = 0; r < 64; )
h[f[r] = r < 26 ? r + 65 : r < 52 ? r + 71 : r < 62 ? r - 4 : r - 59 | 43] = r++;
n.encode = function(t, i, n) {
for (var r, e = null, s = [], u = 0, o = 0; i < n; ) {
var h = t[i++];
switch (o) {
case 0:
s[u++] = f[h >> 2],
r = (3 & h) << 4,
o = 1;
break;
case 1:
s[u++] = f[r | h >> 4],
r = (15 & h) << 2,
o = 2;
break;
case 2:
s[u++] = f[r | h >> 6],
s[u++] = f[63 & h],
o = 0
}
8191 < u && ((e = e || []).push(String.fromCharCode.apply(String, s)),
u = 0)
}
return o && (s[u++] = f[r],
s[u++] = 61,
1 === o && (s[u++] = 61)),
e ? (u && e.push(String.fromCharCode.apply(String, s.slice(0, u))),
e.join("")) : String.fromCharCode.apply(String, s.slice(0, u))
}
;
var c = "invalid encoding";
n.decode = function(t, i, n) {
for (var r, e = n, s = 0, u = 0; u < t.length; ) {
var o = t.charCodeAt(u++);
if (61 == o && 1 < s)
break;
if ((o = h[o]) === g)
throw Error(c);
switch (s) {
case 0:
r = o,
s = 1;
break;
case 1:
i[n++] = r << 2 | (48 & o) >> 4,
r = o,
s = 2;
break;
case 2:
i[n++] = (15 & r) << 4 | (60 & o) >> 2,
r = o,
s = 3;
break;
case 3:
i[n++] = (3 & r) << 6 | o,
s = 0
}
}
if (1 === s)
throw Error(c);
return n - e
}
,
n.test = function(t) {
return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(t)
}
}
, {}],
3: [function(t, i, n) {
function a(i, n) {
"string" == typeof i && (n = i,
i = g);
var h = [];
function f(t) {
if ("string" != typeof t) {
var i = c();
if (a.verbose && console.log("codegen: " + i),
i = "return " + i,
t) {
for (var n = Object.keys(t), r = Array(n.length + 1), e = Array(n.length), s = 0; s < n.length; )
r[s] = n[s],
e[s] = t[n[s++]];
return r[s] = i,
Function.apply(null, r).apply(null, e)
}
return Function(i)()
}
for (var u = Array(arguments.length - 1), o = 0; o < u.length; )
u[o] = arguments[++o];
if (o = 0,
t = t.replace(/%([%dfijs])/g, function(t, i) {
var n = u[o++];
switch (i) {
case "d":
case "f":
return "" + +("" + n);
case "i":
return "" + Math.floor(n);
case "j":
return JSON.stringify(n);
case "s":
return "" + n
}
return "%"
}),
o !== u.length)
throw Error("parameter count mismatch");
return h.push(t),
f
}
function c(t) {
return "function " + (t || n || "") + "(" + (i && i.join(",") || "") + "){\n " + h.join("\n ") + "\n}"
}
return f.toString = c,
f
}
(i.exports = a).verbose = !1
}
, {}],
4: [function(t, i, n) {
function r() {
this.t = {}
}
(i.exports = r).prototype.on = function(t, i, n) {
return (this.t[t] || (this.t[t] = [])).push({
fn: i,
ctx: n || this
}),
this
}
,
r.prototype.off = function(t, i) {
if (t === g)
this.t = {};
else if (i === g)
this.t[t] = [];
else
for (var n = this.t[t], r = 0; r < n.length; )
n[r].fn === i ? n.splice(r, 1) : ++r;
return this
}
,
r.prototype.emit = function(t) {
var i = this.t[t];
if (i) {
for (var n = [], r = 1; r < arguments.length; )
n.push(arguments[r++]);
for (r = 0; r < i.length; )
i[r].fn.apply(i[r++].ctx, n)
}
return this
}
}
, {}],
5: [function(t, i, n) {
i.exports = o;
var s = t(1)
, u = t(7)("fs");
function o(n, r, e) {
return r = "function" == typeof r ? (e = r,
{}) : r || {},
e ? !r.xhr && u && u.readFile ? u.readFile(n, function(t, i) {
return t && "undefined" != typeof XMLHttpRequest ? o.xhr(n, r, e) : t ? e(t) : e(null, r.binary ? i : i.toString("utf8"))
}) : o.xhr(n, r, e) : s(o, this, n, r)
}
o.xhr = function(t, n, r) {
var e = new XMLHttpRequest;
e.onreadystatechange = function() {
if (4 !== e.readyState)
return g;
if (0 !== e.status && 200 !== e.status)
return r(Error("status " + e.status));
if (n.binary) {
if (!(t = e.response))
for (var t = [], i = 0; i < e.responseText.length; ++i)
t.push(255 & e.responseText.charCodeAt(i));
return r(null, "undefined" != typeof Uint8Array ? new Uint8Array(t) : t)
}
return r(null, e.responseText)
}
,
n.binary && ("overrideMimeType"in e && e.overrideMimeType("text/plain; charset=x-user-defined"),
e.responseType = "arraybuffer"),
e.open("GET", t),
e.send()
}
}
, {
1: 1,
7: 7
}],
6: [function(t, i, n) {
function r(t) {
function i(t, i, n, r) {
var e = i < 0 ? 1 : 0;
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)
}
function n(t, i, n) {
t = t(i, n),
i = 2 * (t >> 31) + 1,
n = t >>> 23 & 255,
t &= 8388607;
return 255 == n ? t ? NaN : 1 / 0 * i : 0 == n ? 1401298464324817e-60 * i * t : i * Math.pow(2, n - 150) * (8388608 + t)
}
function r(t, i, n) {
o[0] = t,
i[n] = h[0],
i[n + 1] = h[1],
i[n + 2] = h[2],
i[n + 3] = h[3]
}
function e(t, i, n) {
o[0] = t,
i[n] = h[3],
i[n + 1] = h[2],
i[n + 2] = h[1],
i[n + 3] = h[0]
}
function s(t, i) {
return h[0] = t[i],
h[1] = t[i + 1],
h[2] = t[i + 2],
h[3] = t[i + 3],
o[0]
}
function u(t, i) {
return h[3] = t[i],
h[2] = t[i + 1],
h[1] = t[i + 2],
h[0] = t[i + 3],
o[0]
}
var o, h, f, c, a;
function l(t, i, n, r, e, s) {
var u, o = r < 0 ? 1 : 0;
0 === (r = o ? -r : r) ? (t(0, e, s + i),
t(0 < 1 / r ? 0 : 2147483648, e, s + n)) : isNaN(r) ? (t(0, e, s + i),
t(2146959360, e, s + n)) : 17976931348623157e292 < r ? (t(0, e, s + i),
t((o << 31 | 2146435072) >>> 0, e, s + n)) : r < 22250738585072014e-324 ? (t((u = r / 5e-324) >>> 0, e, s + i),
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),
t((o << 31 | r + 1023 << 20 | 1048576 * u & 1048575) >>> 0, e, s + n))
}
function v(t, i, n, r, e) {
i = t(r, e + i),
r = t(r, e + n),
e = 2 * (r >> 31) + 1,
n = r >>> 20 & 2047,
i = 4294967296 * (1048575 & r) + i;
return 2047 == n ? i ? NaN : 1 / 0 * e : 0 == n ? 5e-324 * e * i : e * Math.pow(2, n - 1075) * (i + 4503599627370496)
}
function d(t, i, n) {
f[0] = t,
i[n] = c[0],
i[n + 1] = c[1],
i[n + 2] = c[2],
i[n + 3] = c[3],
i[n + 4] = c[4],
i[n + 5] = c[5],
i[n + 6] = c[6],
i[n + 7] = c[7]
}
function b(t, i, n) {
f[0] = t,
i[n] = c[7],
i[n + 1] = c[6],
i[n + 2] = c[5],
i[n + 3] = c[4],
i[n + 4] = c[3],
i[n + 5] = c[2],
i[n + 6] = c[1],
i[n + 7] = c[0]
}
function p(t, i) {
return c[0] = t[i],
c[1] = t[i + 1],
c[2] = t[i + 2],
c[3] = t[i + 3],
c[4] = t[i + 4],
c[5] = t[i + 5],
c[6] = t[i + 6],
c[7] = t[i + 7],
f[0]
}
function y(t, i) {
return c[7] = t[i],
c[6] = t[i + 1],
c[5] = t[i + 2],
c[4] = t[i + 3],
c[3] = t[i + 4],
c[2] = t[i + 5],
c[1] = t[i + 6],
c[0] = t[i + 7],
f[0]
}
return "undefined" != typeof Float32Array ? (o = new Float32Array([-0]),
h = new Uint8Array(o.buffer),
a = 128 === h[3],
t.writeFloatLE = a ? r : e,
t.writeFloatBE = a ? e : r,
t.readFloatLE = a ? s : u,
t.readFloatBE = a ? u : s) : (t.writeFloatLE = i.bind(null, m),
t.writeFloatBE = i.bind(null, w),
t.readFloatLE = n.bind(null, g),
t.readFloatBE = n.bind(null, j)),
"undefined" != typeof Float64Array ? (f = new Float64Array([-0]),
c = new Uint8Array(f.buffer),
a = 128 === c[7],
t.writeDoubleLE = a ? d : b,
t.writeDoubleBE = a ? b : d,
t.readDoubleLE = a ? p : y,
t.readDoubleBE = a ? y : p) : (t.writeDoubleLE = l.bind(null, m, 0, 4),
t.writeDoubleBE = l.bind(null, w, 4, 0),
t.readDoubleLE = v.bind(null, g, 0, 4),
t.readDoubleBE = v.bind(null, j, 4, 0)),
t
}
function m(t, i, n) {
i[n] = 255 & t,
i[n + 1] = t >>> 8 & 255,
i[n + 2] = t >>> 16 & 255,
i[n + 3] = t >>> 24
}
function w(t, i, n) {
i[n] = t >>> 24,
i[n + 1] = t >>> 16 & 255,
i[n + 2] = t >>> 8 & 255,
i[n + 3] = 255 & t
}
function g(t, i) {
return (t[i] | t[i + 1] << 8 | t[i + 2] << 16 | t[i + 3] << 24) >>> 0
}
function j(t, i) {
return (t[i] << 24 | t[i + 1] << 16 | t[i + 2] << 8 | t[i + 3]) >>> 0
}
i.exports = r(r)
}
, {}],
7: [function(t, i, n) {
function r(t) {
try {
var i = eval("require")(t);
if (i && (i.length || Object.keys(i).length))
return i
} catch (t) {}
return null
}
i.exports = r
}
, {}],
8: [function(t, i, n) {
var n = n
, e = n.isAbsolute = function(t) {
return /^(?:\/|\w+:)/.test(t)
}
, r = n.normalize = function(t) {
var i = (t = t.replace(/\\/g, "/").replace(/\/{2,}/g, "/")).split("/")
, n = e(t)
, t = "";
n && (t = i.shift() + "/");
for (var r = 0; r < i.length; )
".." === i[r] ? 0 < r && ".." !== i[r - 1] ? i.splice(--r, 2) : n ? i.splice(r, 1) : ++r : "." === i[r] ? i.splice(r, 1) : ++r;
return t + i.join("/")
}
;
n.resolve = function(t, i, n) {
return n || (i = r(i)),
!e(i) && (t = (t = !n ? r(t) : t).replace(/(?:\/|^)[^/]+$/, "")).length ? r(t + "/" + i) : i
}
}
, {}],
9: [function(t, i, n) {
i.exports = function(i, n, t) {
var r = t || 8192
, e = r >>> 1
, s = null
, u = r;
return function(t) {
if (t < 1 || e < t)
return i(t);
r < u + t && (s = i(r),
u = 0);
t = n.call(s, u, u += t);
return 7 & u && (u = 1 + (7 | u)),
t
}
}
}
, {}],
10: [function(t, i, n) {
n.length = function(t) {
for (var i, n = 0, r = 0; r < t.length; ++r)
(i = t.charCodeAt(r)) < 128 ? n += 1 : i < 2048 ? n += 2 : 55296 == (64512 & i) && 56320 == (64512 & t.charCodeAt(r + 1)) ? (++r,
n += 4) : n += 3;
return n
}
,
n.read = function(t, i, n) {
if (n - i < 1)
return "";
for (var r, e = null, s = [], u = 0; i < 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,
s[u++] = 55296 + (r >> 10),
s[u++] = 56320 + (1023 & r)) : s[u++] = (15 & r) << 12 | (63 & t[i++]) << 6 | 63 & t[i++],
8191 < u && ((e = e || []).push(String.fromCharCode.apply(String, s)),
u = 0);
return e ? (u && e.push(String.fromCharCode.apply(String, s.slice(0, u))),
e.join("")) : String.fromCharCode.apply(String, s.slice(0, u))
}
,
n.write = function(t, i, n) {
for (var r, e, s = n, u = 0; u < t.length; ++u)
(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,
i[n++] = (r = 65536 + ((1023 & r) << 10) + (1023 & e)) >> 18 | 240,
i[n++] = r >> 12 & 63 | 128) : i[n++] = r >> 12 | 224,
i[n++] = r >> 6 & 63 | 128),
i[n++] = 63 & r | 128);
return n - s
}
}
, {}],
11: [function(t, i, n) {
var n = n
, l = t(14)
, v = t(33);
function u(t, i, n, r) {
if (i.resolvedType)
if (i.resolvedType instanceof l) {
t("switch(d%s){", r);
for (var e = i.resolvedType.values, s = Object.keys(e), u = 0; u < s.length; ++u)
i.repeated && e[s[u]] === i.typeDefault && t("default:"),
t("case%j:", s[u])("case %i:", e[s[u]])("m%s=%j", r, e[s[u]])("break");
t("}")
} else
t('if(typeof d%s!=="object")', r)("throw TypeError(%j)", i.fullName + ": object expected")("m%s=types[%i].fromObject(d%s)", r, n, r);
else {
var o = !1;
switch (i.type) {
case "double":
case "float":
t("m%s=Number(d%s)", r, r);
break;
case "uint32":
case "fixed32":
t("m%s=d%s>>>0", r, r);
break;
case "int32":
case "sint32":
case "sfixed32":
t("m%s=d%s|0", r, r);
break;
case "uint64":
o = !0;
case "int64":
case "sint64":
case "fixed64":
case "sfixed64":
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" : "");
break;
case "bytes":
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);
break;
case "string":
t("m%s=String(d%s)", r, r);
break;
case "bool":
t("m%s=Boolean(d%s)", r, r)
}
}
return t
}
function d(t, i, n, r) {
if (i.resolvedType)
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);
else {
var e = !1;
switch (i.type) {
case "double":
case "float":
t("d%s=o.json&&!isFinite(m%s)?String(m%s):m%s", r, r, r, r);
break;
case "uint64":
e = !0;
case "int64":
case "sint64":
case "fixed64":
case "sfixed64":
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);
break;
case "bytes":
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);
break;
default:
t("d%s=m%s", r, r)
}
}
return t
}
n.fromObject = function(t) {
var i = t.fieldsArray
, n = v.codegen(["d"], t.name + "$fromObject")("if(d instanceof this.ctor)")("return d");
if (!i.length)
return n("return new this.ctor");
n("var m=new this.ctor");
for (var r = 0; r < i.length; ++r) {
var e = i[r].resolve()
, s = v.safeProp(e.name);
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>>3){");
for (var n = 0; n < t.fieldsArray.length; ++n) {
var r = t.i[n].resolve()
, e = r.resolvedType instanceof o ? "int32" : r.type
, s = "m" + f.safeProp(r.name);
i("case %i:", r.id),
r.map ? (i("if(%s===util.emptyObject)", s)("%s={}", s)("var c2 = r.uint32()+r.pos"),
h.defaults[r.keyType] !== g ? i("k=%j", h.defaults[r.keyType]) : i("k=null"),
h.defaults[e] !== g ? i("value=%j", h.defaults[e]) : i("value=null"),
i("while(r.pos>>3){")("case 1: k=r.%s(); break", r.keyType)("case 2:"),
h.basic[e] === g ? i("value=types[%i].decode(r,r.uint32())", n) : i("value=r.%s()", e),
i("break")("default:")("r.skipType(tag2&7)")("break")("}")("}"),
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),
h.packed[e] !== g && i("if((t&7)===2){")("var c2=r.uint32()+r.pos")("while(r.pos>> 0, 8 | c.mapKey[s.keyType], s.keyType),
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("}")("}")) : s.repeated ? (n("if(%s!=null&&%s.length){", i, i),
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),
h === g ? l(n, s, u, i + "[i]") : n("w.uint32(%i).%s(%s[i])", (s.id << 3 | h) >>> 0, o, i)),
n("}")) : (s.optional && n("if(%s!=null&&Object.hasOwnProperty.call(m,%j))", i, s.name),
h === g ? l(n, s, u, i) : n("w.uint32(%i).%s(%s)", (s.id << 3 | h) >>> 0, o, i))
}
return n("return w")
}
;
var f = t(14)
, c = t(32)
, a = t(33);
function l(t, i, n, r) {
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)
}
}
, {
14: 14,
32: 32,
33: 33
}],
14: [function(t, i, n) {
i.exports = s;
var o = t(22);
((s.prototype = Object.create(o.prototype)).constructor = s).className = "Enum";
var r = t(21)
, e = t(33);
function s(t, i, n, r, e) {
if (o.call(this, t, n),
i && "object" != typeof i)
throw TypeError("values must be an object");
if (this.valuesById = {},
this.values = Object.create(this.valuesById),
this.comment = r,
this.comments = e || {},
this.reserved = g,
i)
for (var s = Object.keys(i), u = 0; u < s.length; ++u)
"number" == typeof i[s[u]] && (this.valuesById[this.values[s[u]] = i[s[u]]] = s[u])
}
s.fromJSON = function(t, i) {
t = new s(t,i.values,i.options,i.comment,i.comments);
return t.reserved = i.reserved,
t
}
,
s.prototype.toJSON = function(t) {
t = !!t && !!t.keepComments;
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])
}
,
s.prototype.add = function(t, i, n) {
if (!e.isString(t))
throw TypeError("name must be a string");
if (!e.isInteger(i))
throw TypeError("id must be an integer");
if (this.values[t] !== g)
throw Error("duplicate name '" + t + "' in " + this);
if (this.isReservedId(i))
throw Error("id " + i + " is reserved in " + this);
if (this.isReservedName(t))
throw Error("name '" + t + "' is reserved in " + this);
if (this.valuesById[i] !== g) {
if (!this.options || !this.options.allow_alias)
throw Error("duplicate id " + i + " in " + this);
this.values[t] = i
} else
this.valuesById[this.values[t] = i] = t;
return this.comments[t] = n || null,
this
}
,
s.prototype.remove = function(t) {
if (!e.isString(t))
throw TypeError("name must be a string");
var i = this.values[t];
if (null == i)
throw Error("name '" + t + "' does not exist in " + this);
return delete this.valuesById[i],
delete this.values[t],
delete this.comments[t],
this
}
,
s.prototype.isReservedId = function(t) {
return r.isReservedId(this.reserved, t)
}
,
s.prototype.isReservedName = function(t) {
return r.isReservedName(this.reserved, t)
}
}
, {
21: 21,
22: 22,
33: 33
}],
15: [function(t, i, n) {
i.exports = u;
var o = t(22);
((u.prototype = Object.create(o.prototype)).constructor = u).className = "Field";
var r, e = t(14), h = t(32), f = t(33), c = /^required|optional|repeated$/;
function u(t, i, n, r, e, s, u) {
if (f.isObject(r) ? (u = e,
s = r,
r = e = g) : f.isObject(e) && (u = s,
s = e,
e = g),
o.call(this, t, s),
!f.isInteger(i) || i < 0)
throw TypeError("id must be a non-negative integer");
if (!f.isString(n))
throw TypeError("type must be a string");
if (r !== g && !c.test(r = r.toString().toLowerCase()))
throw TypeError("rule must be a string rule");
if (e !== g && !f.isString(e))
throw TypeError("extend must be a string");
this.rule = (r = "proto3_optional" === r ? "optional" : r) && "optional" !== r ? r : g,
this.type = n,
this.id = i,
this.extend = e || g,
this.required = "required" === r,
this.optional = !this.required,
this.repeated = "repeated" === r,
this.map = !1,
this.message = null,
this.partOf = null,
this.typeDefault = null,
this.defaultValue = null,
this.long = !!f.Long && h.long[n] !== g,
this.bytes = "bytes" === n,
this.resolvedType = null,
this.extensionField = null,
this.declaringField = null,
this.n = null,
this.comment = u
}
u.fromJSON = function(t, i) {
return new u(t,i.id,i.type,i.rule,i.extend,i.options,i.comment)
}
,
Object.defineProperty(u.prototype, "packed", {
get: function() {
return null === this.n && (this.n = !1 !== this.getOption("packed")),
this.n
}
}),
u.prototype.setOption = function(t, i, n) {
return "packed" === t && (this.n = null),
o.prototype.setOption.call(this, t, i, n)
}
,
u.prototype.toJSON = function(t) {
t = !!t && !!t.keepComments;
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])
}
,
u.prototype.resolve = function() {
return this.resolved ? this : ((this.typeDefault = h.defaults[this.type]) === g && (this.resolvedType = (this.declaringField || this).parent.lookupTypeOrEnum(this.type),
this.resolvedType instanceof r ? this.typeDefault = null : this.typeDefault = this.resolvedType.values[Object.keys(this.resolvedType.values)[0]]),
this.options && null != this.options.default && (this.typeDefault = this.options.default,
this.resolvedType instanceof e && "string" == typeof this.typeDefault && (this.typeDefault = this.resolvedType.values[this.typeDefault])),
this.options && (!0 !== this.options.packed && (this.options.packed === g || !this.resolvedType || this.resolvedType instanceof e) || delete this.options.packed,
Object.keys(this.options).length || (this.options = g)),
this.long ? (this.typeDefault = f.Long.fromNumber(this.typeDefault, "u" == (this.type[0] || "")),
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),
this.typeDefault = t),
this.map ? this.defaultValue = f.emptyObject : this.repeated ? this.defaultValue = f.emptyArray : this.defaultValue = this.typeDefault,
this.parent instanceof r && (this.parent.ctor.prototype[this.name] = this.defaultValue),
o.prototype.resolve.call(this));
var t
}
,
u.d = function(n, r, e, s) {
return "function" == typeof r ? r = f.decorateType(r).name : r && "object" == typeof r && (r = f.decorateEnum(r).name),
function(t, i) {
f.decorateType(t.constructor).add(new u(i,n,r,e,{
default: s
}))
}
}
,
u.r = function(t) {
r = t
}
}
, {
14: 14,
22: 22,
32: 32,
33: 33
}],
16: [function(t, i, n) {
var r = i.exports = t(17);
r.build = "light",
r.load = function(t, i, n) {
return (i = "function" == typeof i ? (n = i,
new r.Root) : i || new r.Root).load(t, n)
}
,
r.loadSync = function(t, i) {
return (i = i || new r.Root).loadSync(t)
}
,
r.encoder = t(13),
r.decoder = t(12),
r.verifier = t(36),
r.converter = t(11),
r.ReflectionObject = t(22),
r.Namespace = t(21),
r.Root = t(26),
r.Enum = t(14),
r.Type = t(31),
r.Field = t(15),
r.OneOf = t(23),
r.MapField = t(18),
r.Service = t(30),
r.Method = t(20),
r.Message = t(19),
r.wrappers = t(37),
r.types = t(32),
r.util = t(33),
r.ReflectionObject.r(r.Root),
r.Namespace.r(r.Type, r.Service, r.Enum),
r.Root.r(r.Type),
r.Field.r(r.Type)
}
, {
11: 11,
12: 12,
13: 13,
14: 14,
15: 15,
17: 17,
18: 18,
19: 19,
20: 20,
21: 21,
22: 22,
23: 23,
26: 26,
30: 30,
31: 31,
32: 32,
33: 33,
36: 36,
37: 37
}],
17: [function(t, i, n) {
var r = n;
function e() {
r.util.r(),
r.Writer.r(r.BufferWriter),
r.Reader.r(r.BufferReader)
}
r.build = "minimal",
r.Writer = t(38),
r.BufferWriter = t(39),
r.Reader = t(24),
r.BufferReader = t(25),
r.util = t(35),
r.rpc = t(28),
r.roots = t(27),
r.configure = e,
e()
}
, {
24: 24,
25: 25,
27: 27,
28: 28,
35: 35,
38: 38,
39: 39
}],
18: [function(t, i, n) {
i.exports = s;
var u = t(15);
((s.prototype = Object.create(u.prototype)).constructor = s).className = "MapField";
var r = t(32)
, o = t(33);
function s(t, i, n, r, e, s) {
if (u.call(this, t, i, r, g, g, e, s),
!o.isString(n))
throw TypeError("keyType must be a string");
this.keyType = n,
this.resolvedKeyType = null,
this.map = !0
}
s.fromJSON = function(t, i) {
return new s(t,i.id,i.keyType,i.type,i.options,i.comment)
}
,
s.prototype.toJSON = function(t) {
t = !!t && !!t.keepComments;
return o.toObject(["keyType", this.keyType, "type", this.type, "id", this.id, "extend", this.extend, "options", this.options, "comment", t ? this.comment : g])
}
,
s.prototype.resolve = function() {
if (this.resolved)
return this;
if (r.mapKey[this.keyType] === g)
throw Error("invalid key type: " + this.keyType);
return u.prototype.resolve.call(this)
}
,
s.d = function(n, r, e) {
return "function" == typeof e ? e = o.decorateType(e).name : e && "object" == typeof e && (e = o.decorateEnum(e).name),
function(t, i) {
o.decorateType(t.constructor).add(new s(i,n,r,e))
}
}
}
, {
15: 15,
32: 32,
33: 33
}],
19: [function(t, i, n) {
i.exports = e;
var r = t(35);
function e(t) {
if (t)
for (var i = Object.keys(t), n = 0; n < i.length; ++n)
this[i[n]] = t[i[n]]
}
e.create = function(t) {
return this.$type.create(t)
}
,
e.encode = function(t, i) {
return this.$type.encode(t, i)
}
,
e.encodeDelimited = function(t, i) {
return this.$type.encodeDelimited(t, i)
}
,
e.decode = function(t) {
return this.$type.decode(t)
}
,
e.decodeDelimited = function(t) {
return this.$type.decodeDelimited(t)
}
,
e.verify = function(t) {
return this.$type.verify(t)
}
,
e.fromObject = function(t) {
return this.$type.fromObject(t)
}
,
e.toObject = function(t, i) {
return this.$type.toObject(t, i)
}
,
e.prototype.toJSON = function() {
return this.$type.toObject(this, r.toJSONOptions)
}
}
, {
35: 35
}],
20: [function(t, i, n) {
i.exports = r;
var f = t(22);
((r.prototype = Object.create(f.prototype)).constructor = r).className = "Method";
var c = t(33);
function r(t, i, n, r, e, s, u, o, h) {
if (c.isObject(e) ? (u = e,
e = s = g) : c.isObject(s) && (u = s,
s = g),
i !== g && !c.isString(i))
throw TypeError("type must be a string");
if (!c.isString(n))
throw TypeError("requestType must be a string");
if (!c.isString(r))
throw TypeError("responseType must be a string");
f.call(this, t, u),
this.type = i || "rpc",
this.requestType = n,
this.requestStream = !!e || g,
this.responseType = r,
this.responseStream = !!s || g,
this.resolvedRequestType = null,
this.resolvedResponseType = null,
this.comment = o,
this.parsedOptions = h
}
r.fromJSON = function(t, i) {
return new r(t,i.type,i.requestType,i.responseType,i.requestStream,i.responseStream,i.options,i.comment,i.parsedOptions)
}
,
r.prototype.toJSON = function(t) {
t = !!t && !!t.keepComments;
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])
}
,
r.prototype.resolve = function() {
return this.resolved ? this : (this.resolvedRequestType = this.parent.lookupType(this.requestType),
this.resolvedResponseType = this.parent.lookupType(this.responseType),
f.prototype.resolve.call(this))
}
}
, {
22: 22,
33: 33
}],
21: [function(t, i, n) {
i.exports = c;
var r = t(22);
((c.prototype = Object.create(r.prototype)).constructor = c).className = "Namespace";
var e, s, u, o = t(15), h = t(33);
function f(t, i) {
if (!t || !t.length)
return g;
for (var n = {}, r = 0; r < t.length; ++r)
n[t[r].name] = t[r].toJSON(i);
return n
}
function c(t, i) {
r.call(this, t, i),
this.nested = g,
this.e = null
}
function a(t) {
return t.e = null,
t
}
c.fromJSON = function(t, i) {
return new c(t,i.options).addJSON(i.nested)
}
,
c.arrayToJSON = f,
c.isReservedId = function(t, i) {
if (t)
for (var n = 0; n < t.length; ++n)
if ("string" != typeof t[n] && t[n][0] <= i && t[n][1] > i)
return !0;
return !1
}
,
c.isReservedName = function(t, i) {
if (t)
for (var n = 0; n < t.length; ++n)
if (t[n] === i)
return !0;
return !1
}
,
Object.defineProperty(c.prototype, "nestedArray", {
get: function() {
return this.e || (this.e = h.toArray(this.nested))
}
}),
c.prototype.toJSON = function(t) {
return h.toObject(["options", this.options, "nested", f(this.nestedArray, t)])
}
,
c.prototype.addJSON = function(t) {
if (t)
for (var i, n = Object.keys(t), r = 0; r < n.length; ++r)
i = t[n[r]],
this.add((i.fields !== g ? e : i.values !== g ? u : i.methods !== g ? s : i.id !== g ? o : c).fromJSON(n[r], i));
return this
}
,
c.prototype.get = function(t) {
return this.nested && this.nested[t] || null
}
,
c.prototype.getEnum = function(t) {
if (this.nested && this.nested[t]instanceof u)
return this.nested[t].values;
throw Error("no such enum: " + t)
}
,
c.prototype.add = function(t) {
if (!(t instanceof o && t.extend !== g || t instanceof e || t instanceof u || t instanceof s || t instanceof c))
throw TypeError("object must be a valid nested object");
if (this.nested) {
var i = this.get(t.name);
if (i) {
if (!(i instanceof c && t instanceof c) || i instanceof e || i instanceof s)
throw Error("duplicate name '" + t.name + "' in " + this);
for (var n = i.nestedArray, r = 0; r < n.length; ++r)
t.add(n[r]);
this.remove(i),
this.nested || (this.nested = {}),
t.setOptions(i.options, !0)
}
} else
this.nested = {};
return (this.nested[t.name] = t).onAdd(this),
a(this)
}
,
c.prototype.remove = function(t) {
if (!(t instanceof r))
throw TypeError("object must be a ReflectionObject");
if (t.parent !== this)
throw Error(t + " is not a member of " + this);
return delete this.nested[t.name],
Object.keys(this.nested).length || (this.nested = g),
t.onRemove(this),
a(this)
}
,
c.prototype.define = function(t, i) {
if (h.isString(t))
t = t.split(".");
else if (!Array.isArray(t))
throw TypeError("illegal path");
if (t && t.length && "" === t[0])
throw Error("path must be relative");
for (var n = this; 0 < t.length; ) {
var r = t.shift();
if (n.nested && n.nested[r]) {
if (!((n = n.nested[r])instanceof c))
throw Error("path conflicts with non-namespace objects")
} else
n.add(n = new c(r))
}
return i && n.addJSON(i),
n
}
,
c.prototype.resolveAll = function() {
for (var t = this.nestedArray, i = 0; i < t.length; )
t[i]instanceof c ? t[i++].resolveAll() : t[i++].resolve();
return this.resolve()
}
,
c.prototype.lookup = function(t, i, n) {
if ("boolean" == typeof i ? (n = i,
i = g) : i && !Array.isArray(i) && (i = [i]),
h.isString(t) && t.length) {
if ("." === t)
return this.root;
t = t.split(".")
} else if (!t.length)
return this;
if ("" === t[0])
return this.root.lookup(t.slice(1), i);
var r = this.get(t[0]);
if (r) {
if (1 === t.length) {
if (!i || ~i.indexOf(r.constructor))
return r
} else if (r instanceof c && (r = r.lookup(t.slice(1), i, !0)))
return r
} else
for (var e = 0; e < this.nestedArray.length; ++e)
if (this.e[e]instanceof c && (r = this.e[e].lookup(t, i, !0)))
return r;
return null === this.parent || n ? null : this.parent.lookup(t, i)
}
,
c.prototype.lookupType = function(t) {
var i = this.lookup(t, [e]);
if (!i)
throw Error("no such type: " + t);
return i
}
,
c.prototype.lookupEnum = function(t) {
var i = this.lookup(t, [u]);
if (!i)
throw Error("no such Enum '" + t + "' in " + this);
return i
}
,
c.prototype.lookupTypeOrEnum = function(t) {
var i = this.lookup(t, [e, u]);
if (!i)
throw Error("no such Type or Enum '" + t + "' in " + this);
return i
}
,
c.prototype.lookupService = function(t) {
var i = this.lookup(t, [s]);
if (!i)
throw Error("no such Service '" + t + "' in " + this);
return i
}
,
c.r = function(t, i, n) {
e = t,
s = i,
u = n
}
}
, {
15: 15,
22: 22,
33: 33
}],
22: [function(t, i, n) {
(i.exports = e).className = "ReflectionObject";
var r, u = t(33);
function e(t, i) {
if (!u.isString(t))
throw TypeError("name must be a string");
if (i && !u.isObject(i))
throw TypeError("options must be an object");
this.options = i,
this.parsedOptions = null,
this.name = t,
this.parent = null,
this.resolved = !1,
this.comment = null,
this.filename = null
}
Object.defineProperties(e.prototype, {
root: {
get: function() {
for (var t = this; null !== t.parent; )
t = t.parent;
return t
}
},
fullName: {
get: function() {
for (var t = [this.name], i = this.parent; i; )
t.unshift(i.name),
i = i.parent;
return t.join(".")
}
}
}),
e.prototype.toJSON = function() {
throw Error()
}
,
e.prototype.onAdd = function(t) {
this.parent && this.parent !== t && this.parent.remove(this),
this.parent = t,
this.resolved = !1;
t = t.root;
t instanceof r && t.u(this)
}
,
e.prototype.onRemove = function(t) {
t = t.root;
t instanceof r && t.o(this),
this.parent = null,
this.resolved = !1
}
,
e.prototype.resolve = function() {
return this.resolved || this.root instanceof r && (this.resolved = !0),
this
}
,
e.prototype.getOption = function(t) {
return this.options ? this.options[t] : g
}
,
e.prototype.setOption = function(t, i, n) {
return n && this.options && this.options[t] !== g || ((this.options || (this.options = {}))[t] = i),
this
}
,
e.prototype.setParsedOption = function(i, t, n) {
this.parsedOptions || (this.parsedOptions = []);
var r, e, s = this.parsedOptions;
return n ? (e = s.find(function(t) {
return Object.prototype.hasOwnProperty.call(t, i)
})) ? (r = e[i],
u.setProperty(r, n, t)) : ((e = {})[i] = u.setProperty({}, n, t),
s.push(e)) : ((e = {})[i] = t,
s.push(e)),
this
}
,
e.prototype.setOptions = function(t, i) {
if (t)
for (var n = Object.keys(t), r = 0; r < n.length; ++r)
this.setOption(n[r], t[n[r]], i);
return this
}
,
e.prototype.toString = function() {
var t = this.constructor.className
, i = this.fullName;
return i.length ? t + " " + i : t
}
,
e.r = function(t) {
r = t
}
}
, {
33: 33
}],
23: [function(t, i, n) {
i.exports = u;
var e = t(22);
((u.prototype = Object.create(e.prototype)).constructor = u).className = "OneOf";
var r = t(15)
, s = t(33);
function u(t, i, n, r) {
if (Array.isArray(i) || (n = i,
i = g),
e.call(this, t, n),
i !== g && !Array.isArray(i))
throw TypeError("fieldNames must be an Array");
this.oneof = i || [],
this.fieldsArray = [],
this.comment = r
}
function o(t) {
if (t.parent)
for (var i = 0; i < t.fieldsArray.length; ++i)
t.fieldsArray[i].parent || t.parent.add(t.fieldsArray[i])
}
u.fromJSON = function(t, i) {
return new u(t,i.oneof,i.options,i.comment)
}
,
u.prototype.toJSON = function(t) {
t = !!t && !!t.keepComments;
return s.toObject(["options", this.options, "oneof", this.oneof, "comment", t ? this.comment : g])
}
,
u.prototype.add = function(t) {
if (!(t instanceof r))
throw TypeError("field must be a Field");
return t.parent && t.parent !== this.parent && t.parent.remove(t),
this.oneof.push(t.name),
this.fieldsArray.push(t),
o(t.partOf = this),
this
}
,
u.prototype.remove = function(t) {
if (!(t instanceof r))
throw TypeError("field must be a Field");
var i = this.fieldsArray.indexOf(t);
if (i < 0)
throw Error(t + " is not a member of " + this);
return this.fieldsArray.splice(i, 1),
-1 < (i = this.oneof.indexOf(t.name)) && this.oneof.splice(i, 1),
t.partOf = null,
this
}
,
u.prototype.onAdd = function(t) {
e.prototype.onAdd.call(this, t);
for (var i = 0; i < this.oneof.length; ++i) {
var n = t.get(this.oneof[i]);
n && !n.partOf && (n.partOf = this).fieldsArray.push(n)
}
o(this)
}
,
u.prototype.onRemove = function(t) {
for (var i, n = 0; n < this.fieldsArray.length; ++n)
(i = this.fieldsArray[n]).parent && i.parent.remove(i);
e.prototype.onRemove.call(this, t)
}
,
u.d = function() {
for (var n = Array(arguments.length), t = 0; t < arguments.length; )
n[t] = arguments[t++];
return function(t, i) {
s.decorateType(t.constructor).add(new u(i,n)),
Object.defineProperty(t, i, {
get: s.oneOfGetter(n),
set: s.oneOfSetter(n)
})
}
}
}
, {
15: 15,
22: 22,
33: 33
}],
24: [function(t, i, n) {
i.exports = h;
var r, e = t(35), s = e.LongBits, u = e.utf8;
function o(t, i) {
return RangeError("index out of range: " + t.pos + " + " + (i || 1) + " > " + t.len)
}
function h(t) {
this.buf = t,
this.pos = 0,
this.len = t.length
}
function f() {
return e.Buffer ? function(t) {
return (h.create = function(t) {
return e.Buffer.isBuffer(t) ? new r(t) : a(t)
}
)(t)
}
: a
}
var c, a = "undefined" != typeof Uint8Array ? function(t) {
if (t instanceof Uint8Array || Array.isArray(t))
return new h(t);
throw Error("illegal buffer")
}
: function(t) {
if (Array.isArray(t))
return new h(t);
throw Error("illegal buffer")
}
;
function l() {
var t = new s(0,0)
, i = 0;
if (!(4 < this.len - this.pos)) {
for (; i < 3; ++i) {
if (this.pos >= this.len)
throw o(this);
if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 7 * i) >>> 0,
this.buf[this.pos++] < 128)
return t
}
return t.lo = (t.lo | (127 & this.buf[this.pos++]) << 7 * i) >>> 0,
t
}
for (; i < 4; ++i)
if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 7 * i) >>> 0,
this.buf[this.pos++] < 128)
return t;
if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 28) >>> 0,
t.hi = (t.hi | (127 & this.buf[this.pos]) >> 4) >>> 0,
this.buf[this.pos++] < 128)
return t;
if (i = 0,
4 < this.len - this.pos) {
for (; i < 5; ++i)
if (t.hi = (t.hi | (127 & this.buf[this.pos]) << 7 * i + 3) >>> 0,
this.buf[this.pos++] < 128)
return t
} else
for (; i < 5; ++i) {
if (this.pos >= this.len)
throw o(this);
if (t.hi = (t.hi | (127 & this.buf[this.pos]) << 7 * i + 3) >>> 0,
this.buf[this.pos++] < 128)
return t
}
throw Error("invalid varint encoding")
}
function v(t, i) {
return (t[i - 4] | t[i - 3] << 8 | t[i - 2] << 16 | t[i - 1] << 24) >>> 0
}
function d() {
if (this.pos + 8 > this.len)
throw o(this, 8);
return new s(v(this.buf, this.pos += 4),v(this.buf, this.pos += 4))
}
h.create = f(),
h.prototype.h = e.Array.prototype.subarray || e.Array.prototype.slice,
h.prototype.uint32 = (c = 4294967295,
function() {
if (c = (127 & this.buf[this.pos]) >>> 0,
this.buf[this.pos++] < 128)
return c;
if (c = (c | (127 & this.buf[this.pos]) << 7) >>> 0,
this.buf[this.pos++] < 128)
return c;
if (c = (c | (127 & this.buf[this.pos]) << 14) >>> 0,
this.buf[this.pos++] < 128)
return c;
if (c = (c | (127 & this.buf[this.pos]) << 21) >>> 0,
this.buf[this.pos++] < 128)
return c;
if (c = (c | (15 & this.buf[this.pos]) << 28) >>> 0,
this.buf[this.pos++] < 128)
return c;
if ((this.pos += 5) > this.len)
throw this.pos = this.len,
o(this, 10);
return c
}
),
h.prototype.int32 = function() {
return 0 | this.uint32()
}
,
h.prototype.sint32 = function() {
var t = this.uint32();
return t >>> 1 ^ -(1 & t) | 0
}
,
h.prototype.bool = function() {
return 0 !== this.uint32()
}
,
h.prototype.fixed32 = function() {
if (this.pos + 4 > this.len)
throw o(this, 4);
return v(this.buf, this.pos += 4)
}
,
h.prototype.sfixed32 = function() {
if (this.pos + 4 > this.len)
throw o(this, 4);
return 0 | v(this.buf, this.pos += 4)
}
,
h.prototype.float = function() {
if (this.pos + 4 > this.len)
throw o(this, 4);
var t = e.float.readFloatLE(this.buf, this.pos);
return this.pos += 4,
t
}
,
h.prototype.double = function() {
if (this.pos + 8 > this.len)
throw o(this, 4);
var t = e.float.readDoubleLE(this.buf, this.pos);
return this.pos += 8,
t
}
,
h.prototype.bytes = function() {
var t = this.uint32()
, i = this.pos
, n = this.pos + t;
if (n > this.len)
throw o(this, t);
return this.pos += t,
Array.isArray(this.buf) ? this.buf.slice(i, n) : i === n ? new this.buf.constructor(0) : this.h.call(this.buf, i, n)
}
,
h.prototype.string = function() {
var t = this.bytes();
return u.read(t, 0, t.length)
}
,
h.prototype.skip = function(t) {
if ("number" == typeof t) {
if (this.pos + t > this.len)
throw o(this, t);
this.pos += t
} else
do {
if (this.pos >= this.len)
throw o(this)
} while (128 & this.buf[this.pos++]);
return this
}
,
h.prototype.skipType = function(t) {
switch (t) {
case 0:
this.skip();
break;
case 1:
this.skip(8);
break;
case 2:
this.skip(this.uint32());
break;
case 3:
for (; 4 != (t = 7 & this.uint32()); )
this.skipType(t);
break;
case 5:
this.skip(4);
break;
default:
throw Error("invalid wire type " + t + " at offset " + this.pos)
}
return this
}
,
h.r = function(t) {
r = t,
h.create = f(),
r.r();
var i = e.Long ? "toLong" : "toNumber";
e.merge(h.prototype, {
int64: function() {
return l.call(this)[i](!1)
},
uint64: function() {
return l.call(this)[i](!0)
},
sint64: function() {
return l.call(this).zzDecode()[i](!1)
},
fixed64: function() {
return d.call(this)[i](!0)
},
sfixed64: function() {
return d.call(this)[i](!1)
}
})
}
}
, {
35: 35
}],
25: [function(t, i, n) {
i.exports = s;
var r = t(24);
(s.prototype = Object.create(r.prototype)).constructor = s;
var e = t(35);
function s(t) {
r.call(this, t)
}
s.r = function() {
e.Buffer && (s.prototype.h = e.Buffer.prototype.slice)
}
,
s.prototype.string = function() {
var t = this.uint32();
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))
}
,
s.r()
}
, {
24: 24,
35: 35
}],
26: [function(t, i, n) {
i.exports = h;
var r = t(21);
((h.prototype = Object.create(r.prototype)).constructor = h).className = "Root";
var e, v, d, s = t(15), u = t(14), o = t(23), b = t(33);
function h(t) {
r.call(this, "", t),
this.deferred = [],
this.files = []
}
function p() {}
h.fromJSON = function(t, i) {
return i = i || new h,
t.options && i.setOptions(t.options),
i.addJSON(t.nested)
}
,
h.prototype.resolvePath = b.path.resolve,
h.prototype.fetch = b.fetch,
h.prototype.load = function t(i, s, e) {
"function" == typeof s && (e = s,
s = g);
var u = this;
if (!e)
return b.asPromise(t, u, i, s);
var o = e === p;
function h(t, i) {
if (e) {
var n = e;
if (e = null,
o)
throw t;
n(t, i)
}
}
function f(t) {
var i = t.lastIndexOf("google/protobuf/");
if (-1 < i) {
i = t.substring(i);
if (i in d)
return i
}
return null
}
function c(t, i) {
try {
if (b.isString(i) && "{" == (i[0] || "") && (i = JSON.parse(i)),
b.isString(i)) {
v.filename = t;
var n, r = v(i, u, s), e = 0;
if (r.imports)
for (; e < r.imports.length; ++e)
(n = f(r.imports[e]) || u.resolvePath(t, r.imports[e])) && a(n);
if (r.weakImports)
for (e = 0; e < r.weakImports.length; ++e)
(n = f(r.weakImports[e]) || u.resolvePath(t, r.weakImports[e])) && a(n, !0)
} else
u.setOptions(i.options).addJSON(i.nested)
} catch (t) {
h(t)
}
o || l || h(null, u)
}
function a(n, r) {
if (!~u.files.indexOf(n))
if (u.files.push(n),
n in d)
o ? c(n, d[n]) : (++l,
setTimeout(function() {
--l,
c(n, d[n])
}));
else if (o) {
var t;
try {
t = b.fs.readFileSync(n).toString("utf8")
} catch (t) {
return void (r || h(t))
}
c(n, t)
} else
++l,
u.fetch(n, function(t, i) {
--l,
e && (t ? r ? l || h(null, u) : h(t) : c(n, i))
})
}
var l = 0;
b.isString(i) && (i = [i]);
for (var n, r = 0; r < i.length; ++r)
(n = u.resolvePath("", i[r])) && a(n);
return o ? u : (l || h(null, u),
g)
}
,
h.prototype.loadSync = function(t, i) {
if (!b.isNode)
throw Error("not supported");
return this.load(t, i, p)
}
,
h.prototype.resolveAll = function() {
if (this.deferred.length)
throw Error("unresolvable extensions: " + this.deferred.map(function(t) {
return "'extend " + t.extend + "' in " + t.parent.fullName
}).join(", "));
return r.prototype.resolveAll.call(this)
}
;
var f = /^[A-Z]/;
function c(t, i) {
var n = i.parent.lookup(i.extend);
if (n) {
var r = new s(i.fullName,i.id,i.type,i.rule,g,i.options);
return (r.declaringField = i).extensionField = r,
n.add(r),
1
}
}
h.prototype.u = function(t) {
if (t instanceof s)
t.extend === g || t.extensionField || c(0, t) || this.deferred.push(t);
else if (t instanceof u)
f.test(t.name) && (t.parent[t.name] = t.values);
else if (!(t instanceof o)) {
if (t instanceof e)
for (var i = 0; i < this.deferred.length; )
c(0, this.deferred[i]) ? this.deferred.splice(i, 1) : ++i;
for (var n = 0; n < t.nestedArray.length; ++n)
this.u(t.e[n]);
f.test(t.name) && (t.parent[t.name] = t)
}
}
,
h.prototype.o = function(t) {
var i;
if (t instanceof s)
t.extend !== g && (t.extensionField ? (t.extensionField.parent.remove(t.extensionField),
t.extensionField = null) : -1 < (i = this.deferred.indexOf(t)) && this.deferred.splice(i, 1));
else if (t instanceof u)
f.test(t.name) && delete t.parent[t.name];
else if (t instanceof r) {
for (var n = 0; n < t.nestedArray.length; ++n)
this.o(t.e[n]);
f.test(t.name) && delete t.parent[t.name]
}
}
,
h.r = function(t, i, n) {
e = t,
v = i,
d = n
}
}
, {
14: 14,
15: 15,
21: 21,
23: 23,
33: 33
}],
27: [function(t, i, n) {
i.exports = {}
}
, {}],
28: [function(t, i, n) {
n.Service = t(29)
}
, {
29: 29
}],
29: [function(t, i, n) {
i.exports = r;
var o = t(35);
function r(t, i, n) {
if ("function" != typeof t)
throw TypeError("rpcImpl must be a function");
o.EventEmitter.call(this),
this.rpcImpl = t,
this.requestDelimited = !!i,
this.responseDelimited = !!n
}
((r.prototype = Object.create(o.EventEmitter.prototype)).constructor = r).prototype.rpcCall = function t(n, i, r, e, s) {
if (!e)
throw TypeError("request must be specified");
var u = this;
if (!s)
return o.asPromise(t, u, n, i, r, e);
if (!u.rpcImpl)
return setTimeout(function() {
s(Error("already ended"))
}, 0),
g;
try {
return u.rpcImpl(n, i[u.requestDelimited ? "encodeDelimited" : "encode"](e).finish(), function(t, i) {
if (t)
return u.emit("error", t, n),
s(t);
if (null === i)
return u.end(!0),
g;
if (!(i instanceof r))
try {
i = r[u.responseDelimited ? "decodeDelimited" : "decode"](i)
} catch (t) {
return u.emit("error", t, n),
s(t)
}
return u.emit("data", i, n),
s(null, i)
})
} catch (t) {
return u.emit("error", t, n),
setTimeout(function() {
s(t)
}, 0),
g
}
}
,
r.prototype.end = function(t) {
return this.rpcImpl && (t || this.rpcImpl(null, null, null),
this.rpcImpl = null,
this.emit("end").off()),
this
}
}
, {
35: 35
}],
30: [function(t, i, n) {
i.exports = u;
var r = t(21);
((u.prototype = Object.create(r.prototype)).constructor = u).className = "Service";
var s = t(20)
, o = t(33)
, h = t(28);
function u(t, i) {
r.call(this, t, i),
this.methods = {},
this.f = null
}
function e(t) {
return t.f = null,
t
}
u.fromJSON = function(t, i) {
var n = new u(t,i.options);
if (i.methods)
for (var r = Object.keys(i.methods), e = 0; e < r.length; ++e)
n.add(s.fromJSON(r[e], i.methods[r[e]]));
return i.nested && n.addJSON(i.nested),
n.comment = i.comment,
n
}
,
u.prototype.toJSON = function(t) {
var i = r.prototype.toJSON.call(this, t)
, n = !!t && !!t.keepComments;
return o.toObject(["options", i && i.options || g, "methods", r.arrayToJSON(this.methodsArray, t) || {}, "nested", i && i.nested || g, "comment", n ? this.comment : g])
}
,
Object.defineProperty(u.prototype, "methodsArray", {
get: function() {
return this.f || (this.f = o.toArray(this.methods))
}
}),
u.prototype.get = function(t) {
return this.methods[t] || r.prototype.get.call(this, t)
}
,
u.prototype.resolveAll = function() {
for (var t = this.methodsArray, i = 0; i < t.length; ++i)
t[i].resolve();
return r.prototype.resolve.call(this)
}
,
u.prototype.add = function(t) {
if (this.get(t.name))
throw Error("duplicate name '" + t.name + "' in " + this);
return t instanceof s ? e((this.methods[t.name] = t).parent = this) : r.prototype.add.call(this, t)
}
,
u.prototype.remove = function(t) {
if (t instanceof s) {
if (this.methods[t.name] !== t)
throw Error(t + " is not a member of " + this);
return delete this.methods[t.name],
t.parent = null,
e(this)
}
return r.prototype.remove.call(this, t)
}
,
u.prototype.create = function(t, i, n) {
for (var r, e = new h.Service(t,i,n), s = 0; s < this.methodsArray.length; ++s) {
var u = o.lcFirst((r = this.f[s]).resolve().name).replace(/[^$\w_]/g, "");
e[u] = o.codegen(["r", "c"], o.isReserved(u) ? u + "_" : u)("return this.rpcCall(m,q,s,r,c)")({
m: r,
q: r.resolvedRequestType.ctor,
s: r.resolvedResponseType.ctor
})
}
return e
}
}
, {
20: 20,
21: 21,
28: 28,
33: 33
}],
31: [function(t, i, n) {
i.exports = w;
var u = t(21);
((w.prototype = Object.create(u.prototype)).constructor = w).className = "Type";
var o = t(14)
, h = t(23)
, f = t(15)
, c = t(18)
, a = t(30)
, e = t(19)
, s = t(24)
, l = t(38)
, v = t(33)
, d = t(13)
, b = t(12)
, p = t(36)
, y = t(11)
, m = t(37);
function w(t, i) {
u.call(this, t, i),
this.fields = {},
this.oneofs = g,
this.extensions = g,
this.reserved = g,
this.group = g,
this.c = null,
this.i = null,
this.a = null,
this.l = null
}
function r(t) {
return t.c = t.i = t.a = null,
delete t.encode,
delete t.decode,
delete t.verify,
t
}
Object.defineProperties(w.prototype, {
fieldsById: {
get: function() {
if (this.c)
return this.c;
this.c = {};
for (var t = Object.keys(this.fields), i = 0; i < t.length; ++i) {
var n = this.fields[t[i]]
, r = n.id;
if (this.c[r])
throw Error("duplicate id " + r + " in " + this);
this.c[r] = n
}
return this.c
}
},
fieldsArray: {
get: function() {
return this.i || (this.i = v.toArray(this.fields))
}
},
oneofsArray: {
get: function() {
return this.a || (this.a = v.toArray(this.oneofs))
}
},
ctor: {
get: function() {
return this.l || (this.ctor = w.generateConstructor(this)())
},
set: function(t) {
var i = t.prototype;
i instanceof e || ((t.prototype = new e).constructor = t,
v.merge(t.prototype, i)),
t.$type = t.prototype.$type = this,
v.merge(t, e, !0),
this.l = t;
for (var n = 0; n < this.fieldsArray.length; ++n)
this.i[n].resolve();
for (var r = {}, n = 0; n < this.oneofsArray.length; ++n)
r[this.a[n].resolve().name] = {
get: v.oneOfGetter(this.a[n].oneof),
set: v.oneOfSetter(this.a[n].oneof)
};
n && Object.defineProperties(t.prototype, r)
}
}
}),
w.generateConstructor = function(t) {
for (var i, n = v.codegen(["p"], t.name), r = 0; r < t.fieldsArray.length; ++r)
(i = t.i[r]).map ? n("this%s={}", v.safeProp(i.name)) : i.repeated && n("this%s=[]", v.safeProp(i.name));
return n("if(p)for(var ks=Object.keys(p),i=0;i>> 0,
this.hi = i >>> 0
}
var s = e.zero = new e(0,0);
s.toNumber = function() {
return 0
}
,
s.zzEncode = s.zzDecode = function() {
return this
}
,
s.length = function() {
return 1
}
;
e.zeroHash = "\0\0\0\0\0\0\0\0";
e.fromNumber = function(t) {
if (0 === t)
return s;
var i = t < 0
, n = (t = i ? -t : t) >>> 0
, t = (t - n) / 4294967296 >>> 0;
return i && (t = ~t >>> 0,
n = ~n >>> 0,
4294967295 < ++n && (n = 0,
4294967295 < ++t && (t = 0))),
new e(n,t)
}
,
e.from = function(t) {
if ("number" == typeof t)
return e.fromNumber(t);
if (r.isString(t)) {
if (!r.Long)
return e.fromNumber(parseInt(t, 10));
t = r.Long.fromString(t)
}
return t.low || t.high ? new e(t.low >>> 0,t.high >>> 0) : s
}
,
e.prototype.toNumber = function(t) {
if (!t && this.hi >>> 31) {
var i = 1 + ~this.lo >>> 0
, t = ~this.hi >>> 0;
return -(i + 4294967296 * (t = !i ? t + 1 >>> 0 : t))
}
return this.lo + 4294967296 * this.hi
}
,
e.prototype.toLong = function(t) {
return r.Long ? new r.Long(0 | this.lo,0 | this.hi,!!t) : {
low: 0 | this.lo,
high: 0 | this.hi,
unsigned: !!t
}
}
;
var u = String.prototype.charCodeAt;
e.fromHash = function(t) {
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)
}
,
e.prototype.toHash = function() {
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)
}
,
e.prototype.zzEncode = function() {
var t = this.hi >> 31;
return this.hi = ((this.hi << 1 | this.lo >>> 31) ^ t) >>> 0,
this.lo = (this.lo << 1 ^ t) >>> 0,
this
}
,
e.prototype.zzDecode = function() {
var t = -(1 & this.lo);
return this.lo = ((this.lo >>> 1 | this.hi << 31) ^ t) >>> 0,
this.hi = (this.hi >>> 1 ^ t) >>> 0,
this
}
,
e.prototype.length = function() {
var t = this.lo
, i = (this.lo >>> 28 | this.hi << 4) >>> 0
, n = this.hi >>> 24;
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
}
}
, {
35: 35
}],
35: [function(t, i, n) {
var r = n;
function e(t, i, n) {
for (var r = Object.keys(i), e = 0; e < r.length; ++e)
t[r[e]] !== g && n || (t[r[e]] = i[r[e]]);
return t
}
function s(t) {
function n(t, i) {
if (!(this instanceof n))
return new n(t,i);
Object.defineProperty(this, "message", {
get: function() {
return t
}
}),
Error.captureStackTrace ? Error.captureStackTrace(this, n) : Object.defineProperty(this, "stack", {
value: Error().stack || ""
}),
i && e(this, i)
}
return (n.prototype = Object.create(Error.prototype)).constructor = n,
Object.defineProperty(n.prototype, "name", {
get: function() {
return t
}
}),
n.prototype.toString = function() {
return this.name + ": " + this.message
}
,
n
}
r.asPromise = t(1),
r.base64 = t(2),
r.EventEmitter = t(4),
r.float = t(6),
r.inquire = t(7),
r.utf8 = t(10),
r.pool = t(9),
r.LongBits = t(34),
r.isNode = !!("undefined" != typeof global && global && global.process && global.process.versions && global.process.versions.node),
r.global = r.isNode && global || "undefined" != typeof window && window || "undefined" != typeof self && self || this,
r.emptyArray = Object.freeze ? Object.freeze([]) : [],
r.emptyObject = Object.freeze ? Object.freeze({}) : {},
r.isInteger = Number.isInteger || function(t) {
return "number" == typeof t && isFinite(t) && Math.floor(t) === t
}
,
r.isString = function(t) {
return "string" == typeof t || t instanceof String
}
,
r.isObject = function(t) {
return t && "object" == typeof t
}
,
r.isset = r.isSet = function(t, i) {
var n = t[i];
return null != n && t.hasOwnProperty(i) && ("object" != typeof n || 0 < (Array.isArray(n) ? n : Object.keys(n)).length)
}
,
r.Buffer = function() {
try {
var t = r.inquire("buffer").Buffer;
return t.prototype.utf8Write ? t : null
} catch (t) {
return null
}
}(),
r.v = null,
r.b = null,
r.newBuffer = function(t) {
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)
}
,
r.Array = "undefined" != typeof Uint8Array ? Uint8Array : Array,
r.Long = r.global.dcodeIO && r.global.dcodeIO.Long || r.global.Long || r.inquire("long"),
r.key2Re = /^true|false|0|1$/,
r.key32Re = /^-?(?:0|[1-9][0-9]*)$/,
r.key64Re = /^(?:[\\x00-\\xff]{8}|-?(?:0|[1-9][0-9]*))$/,
r.longToHash = function(t) {
return t ? r.LongBits.from(t).toHash() : r.LongBits.zeroHash
}
,
r.longFromHash = function(t, i) {
t = r.LongBits.fromHash(t);
return r.Long ? r.Long.fromBits(t.lo, t.hi, i) : t.toNumber(!!i)
}
,
r.merge = e,
r.lcFirst = function(t) {
return (t[0] || "").toLowerCase() + t.substring(1)
}
,
r.newError = s,
r.ProtocolError = s("ProtocolError"),
r.oneOfGetter = function(t) {
for (var n = {}, i = 0; i < t.length; ++i)
n[t[i]] = 1;
return function() {
for (var t = Object.keys(this), i = t.length - 1; -1 < i; --i)
if (1 === n[t[i]] && this[t[i]] !== g && null !== this[t[i]])
return t[i]
}
}
,
r.oneOfSetter = function(n) {
return function(t) {
for (var i = 0; i < n.length; ++i)
n[i] !== t && delete this[n[i]]
}
}
,
r.toJSONOptions = {
longs: String,
enums: String,
bytes: String,
json: !0
},
r.r = function() {
var n = r.Buffer;
n ? (r.v = n.from !== Uint8Array.from && n.from || function(t, i) {
return new n(t,i)
}
,
r.b = n.allocUnsafe || function(t) {
return new n(t)
}
) : r.v = r.b = null
}
}
, {
1: 1,
10: 10,
2: 2,
34: 34,
4: 4,
6: 6,
7: 7,
9: 9
}],
36: [function(t, i, n) {
i.exports = function(t) {
var i = h.codegen(["m"], t.name + "$verify")('if(typeof m!=="object"||m===null)')("return%j", "object expected")
, n = t.oneofsArray
, r = {};
n.length && i("var p={}");
for (var e = 0; e < t.fieldsArray.length; ++e) {
var s, u = t.i[e].resolve(), o = "m" + h.safeProp(u.name);
u.optional && i("if(%s!=null&&m.hasOwnProperty(%j)){", o, u.name),
u.map ? (i("if(!util.isObject(%s))", o)("return%j", f(u, "object"))("var k=Object.keys(%s)", o)("for(var i=0;i>> 7 | t.hi << 25) >>> 0,
t.hi >>>= 7;
for (; 127 < t.lo; )
i[n++] = 127 & t.lo | 128,
t.lo = t.lo >>> 7;
i[n++] = t.lo
}
function p(t, i, n) {
i[n] = 255 & t,
i[n + 1] = t >>> 8 & 255,
i[n + 2] = t >>> 16 & 255,
i[n + 3] = t >>> 24
}
a.create = l(),
a.alloc = function(t) {
return new e.Array(t)
}
,
e.Array !== Array && (a.alloc = e.pool(a.alloc, e.Array.prototype.subarray)),
a.prototype.p = function(t, i, n) {
return this.tail = this.tail.next = new h(t,i,n),
this.len += i,
this
}
,
(d.prototype = Object.create(h.prototype)).fn = function(t, i, n) {
for (; 127 < t; )
i[n++] = 127 & t | 128,
t >>>= 7;
i[n] = t
}
,
a.prototype.uint32 = function(t) {
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,
this
}
,
a.prototype.int32 = function(t) {
return t < 0 ? this.p(b, 10, s.fromNumber(t)) : this.uint32(t)
}
,
a.prototype.sint32 = function(t) {
return this.uint32((t << 1 ^ t >> 31) >>> 0)
}
,
a.prototype.int64 = a.prototype.uint64 = function(t) {
t = s.from(t);
return this.p(b, t.length(), t)
}
,
a.prototype.sint64 = function(t) {
t = s.from(t).zzEncode();
return this.p(b, t.length(), t)
}
,
a.prototype.bool = function(t) {
return this.p(v, 1, t ? 1 : 0)
}
,
a.prototype.sfixed32 = a.prototype.fixed32 = function(t) {
return this.p(p, 4, t >>> 0)
}
,
a.prototype.sfixed64 = a.prototype.fixed64 = function(t) {
t = s.from(t);
return this.p(p, 4, t.lo).p(p, 4, t.hi)
}
,
a.prototype.float = function(t) {
return this.p(e.float.writeFloatLE, 4, t)
}
,
a.prototype.double = function(t) {
return this.p(e.float.writeDoubleLE, 8, t)
}
;
var y = e.Array.prototype.set ? function(t, i, n) {
i.set(t, n)
}
: function(t, i, n) {
for (var r = 0; r < t.length; ++r)
i[n + r] = t[r]
}
;
a.prototype.bytes = function(t) {
var i, n = t.length >>> 0;
return n ? (e.isString(t) && (i = a.alloc(n = u.length(t)),
u.decode(t, i, 0),
t = i),
this.uint32(n).p(y, n, t)) : this.p(v, 1, 0)
}
,
a.prototype.string = function(t) {
var i = o.length(t);
return i ? this.uint32(i).p(o.write, i, t) : this.p(v, 1, 0)
}
,
a.prototype.fork = function() {
return this.states = new c(this),
this.head = this.tail = new h(f,0,0),
this.len = 0,
this
}
,
a.prototype.reset = function() {
return this.states ? (this.head = this.states.head,
this.tail = this.states.tail,
this.len = this.states.len,
this.states = this.states.next) : (this.head = this.tail = new h(f,0,0),
this.len = 0),
this
}
,
a.prototype.ldelim = function() {
var t = this.head
, i = this.tail
, n = this.len;
return this.reset().uint32(n),
n && (this.tail.next = t.next,
this.tail = i,
this.len += n),
this
}
,
a.prototype.finish = function() {
for (var t = this.head.next, i = this.constructor.alloc(this.len), n = 0; t; )
t.fn(t.val, i, n),
n += t.len,
t = t.next;
return i
}
,
a.r = function(t) {
r = t,
a.create = l(),
r.r()
}
}
, {
35: 35
}],
39: [function(t, i, n) {
i.exports = s;
var r = t(38);
(s.prototype = Object.create(r.prototype)).constructor = s;
var e = t(35);
function s() {
r.call(this)
}
function u(t, i, n) {
t.length < 40 ? e.utf8.write(t, i, n) : i.utf8Write ? i.utf8Write(t, n) : i.write(t, n)
}
s.r = function() {
s.alloc = e.b,
s.writeBytesBuffer = e.Buffer && e.Buffer.prototype instanceof Uint8Array && "set" === e.Buffer.prototype.set.name ? function(t, i, n) {
i.set(t, n)
}
: function(t, i, n) {
if (t.copy)
t.copy(i, n, 0, t.length);
else
for (var r = 0; r < t.length; )
i[n++] = t[r++]
}
}
,
s.prototype.bytes = function(t) {
var i = (t = e.isString(t) ? e.v(t, "base64") : t).length >>> 0;
return this.uint32(i),
i && this.p(s.writeBytesBuffer, i, t),
this
}
,
s.prototype.string = function(t) {
var i = e.Buffer.byteLength(t);
return this.uint32(i),
i && this.p(u, i, t),
this
}
,
s.r()
}
, {
35: 35,
38: 38
}]
},
e = {},
t = [16],
i = function t(i) {
var n = e[i];
return n || r[i][0].call(n = e[i] = {
exports: {}
}, t, n, n.exports),
n.exports
}(t[0]),
i.util.global.protobuf = i,
"function" == typeof define && define.amd && define(["long"], function(t) {
return t && t.isLong && (i.util.Long = t,
i.configure()),
i
}),
"object" == typeof module && module && module.exports && (module.exports = i)
aaa =i;
}();
//# sourceMappingURL=protobuf.min.js.map
function PolicyInfoByTypeIdParam_encode(m){
w= aaa.Writer.create()
if(m.policyType!=null&&Object.hasOwnProperty.call(m,"policyType"))
w.uint32(10).string(m.policyType)
if(m.centralId!=null&&Object.hasOwnProperty.call(m,"centralId"))
w.uint32(18).string(m.centralId)
if(m.province!=null&&Object.hasOwnProperty.call(m,"province"))
w.uint32(26).string(m.province)
if(m.city!=null&&Object.hasOwnProperty.call(m,"city"))
w.uint32(34).string(m.city)
if(m.downtown!=null&&Object.hasOwnProperty.call(m,"downtown"))
w.uint32(42).string(m.downtown)
if(m.garden!=null&&Object.hasOwnProperty.call(m,"garden"))
w.uint32(50).string(m.garden)
if(m.sort!=null&&Object.hasOwnProperty.call(m,"sort"))
w.uint32(56).uint32(m.sort)
if(m.pageNum!=null&&Object.hasOwnProperty.call(m,"pageNum"))
w.uint32(64).uint32(m.pageNum)
if(m.pageSize!=null&&Object.hasOwnProperty.call(m,"pageSize"))
w.uint32(72).uint32(m.pageSize)
return w
}
data = {
centralId: "",
city: "",
downtown: "",
garden: "",
pageNum: 1,
pageSize: 7,
policyType: "6",
province: "",
sort: 0
}
body = PolicyInfoByTypeIdParam_encode(data).finish().slice()
let e={ "url":"http://www.spolicy.com/info_api/policyType/showPolicyType",
"method":"POST",
"data" : body};
var h = new XMLHttpRequest;h.open(e.method, e.url, true);
h.setRequestHeader("accept","application/json, text/plain, */*");
h.setRequestHeader("content-type","application/octet-stream");
h.onreadystatechange=function(){
if (h.status===200){
console.log(h)
}
}
h.send(e.data);
================================================
FILE: 第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例二.js
================================================
function reqId() {
var t = {};
var e = undefined;
var n = undefined;
var r = [123, 48, 115, 203, 231, 115];
var o = 9996;
var d = 0;
var h = Date.now();
var i = e && n || 0
, b = e || []
, f = (t = t || {}).node || r
, v = void 0 !== t.clockseq ? t.clockseq : o;
if (null == f || null == v) {
var m = l();
null == f && (f = r = [1 | m[0], m[1], m[2], m[3], m[4], m[5]]),
null == v && (v = o = 16383 & (m[6] << 8 | m[7]))
}
var y = void 0 !== t.msecs ? t.msecs : (new Date).getTime()
, w = void 0 !== t.nsecs ? t.nsecs : d + 1
, dt = y - h + (w - d) / 1e4;
if (dt < 0 && void 0 === t.clockseq && (v = v + 1 & 16383),
(dt < 0 || y > h) && void 0 === t.nsecs && (w = 0),
w >= 1e4)
throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");
h = y,
d = w,
o = v;
var x = (1e4 * (268435455 & (y += 122192928e5)) + w) % 4294967296;
b[i++] = x >>> 24 & 255,
b[i++] = x >>> 16 & 255,
b[i++] = x >>> 8 & 255,
b[i++] = 255 & x;
var _ = y / 4294967296 * 1e4 & 268435455;
b[i++] = _ >>> 8 & 255,
b[i++] = 255 & _,
b[i++] = _ >>> 24 & 15 | 16,
b[i++] = _ >>> 16 & 255,
b[i++] = v >>> 8 | 128,
b[i++] = 255 & v;
for (var A = 0; A < 6; ++A)
b[i + A] = f[A];
return e || c(b)
}
function c(t, e) {
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"];
var i = e || 0
, r = 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("")
}
console.log(reqId())
================================================
FILE: 第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.7 lsb隐写/lsb.py
================================================
from PIL import Image
def plus(str):
# 返回指定长度的字符串,原字符串右对齐,前面填充0。
return str.zfill(8)
def get_key(strr):
str_ = ""
for i in range(len(strr)):
# 将要隐藏的文件内容转换为二进制并拼接起来
str_ = str_ + plus(bin(ord(strr[i])).replace('0b', ''))
return str_
def mod(x, y):
return x % y
def func(old_img, str2, new_img):
# str1为载体图片路径,str2为隐写文件,str3为加密图片保存的路径
im = Image.open(old_img)
# 获取图片的宽和高
width = im.size[0]
height = im.size[1]
count = 0
key = get_key(str2)
keylen = len(key)
for h in range(0, height):
for w in range(0, width):
pixel = im.getpixel((w, h))
a = pixel[0]
b = pixel[1]
c = pixel[2]
if count == keylen:
break
# 信息隐藏:分别将每个像素点的RGB值余2,去掉最低位的值
# 再从需要隐藏的信息中取出一位,转换为整型,两值相加
a = a - mod(a, 2) + int(key[count])
count += 1
if count == keylen:
im.putpixel((w, h), (a, b, c))
break
b = b - mod(b, 2) + int(key[count])
count += 1
if count == keylen:
im.putpixel((w, h), (a, b, c))
break
c = c - mod(c, 2) + int(key[count])
count += 1
if count == keylen:
im.putpixel((w, h), (a, b, c))
break
if count % 3 == 0:
im.putpixel((w, h), (a, b, c))
im.save(new_img)
# 原图
old_img = r"timg.jpg"
new_img = r"timg2.jpg"
func(old_img,"Lx Is Good Man",new_img)
================================================
FILE: 第三章:Web Js逆向/3.5 常见的编码和加密/3.5.6 AES/aes_encrypt.js
================================================
let password = "lx123";
let key = "1234567890abcdef"
// AES加密
cfg = {
mode: CryptoJs.mode.ECB,
padding: CryptoJs.pad.Pkcs7
}
let encPwd = CryptoJs.AES.encrypt(password, key, cfg).toString()
// AES解密
let key = CryptoJs.enc.Utf8.parse("1234567890abcdef")
cfg = {
mode: CryptoJs.mode.ECB,
padding: CryptoJs.pad.Pkcs7
}
encPwd = "+4X1GzDcLdd5yb3PiZLxdw=="
decPwd = CryptoJs.AES.decrypt(encPwd, key, cfg).toString(CryptoJs.enc.Utf8) // 指定解码方式
console.log(decPwd) // lx123
================================================
FILE: 第三章:Web Js逆向/3.5 常见的编码和加密/3.5.6 AES/aes_encrypt.py
================================================
import base64
from Crypto.Cipher import AES
# AES
# 需要补位,str不是16的倍数那就补足为16的倍数
def add_to_16(value):
while len(value) % 16 != 0:
value += '\0'
return str.encode(value) # 返回bytes
# 加密方法
def encrypt(key, text):
aes = AES.new(add_to_16(key), AES.MODE_ECB) # 初始化加密器
encrypt_aes = aes.encrypt(add_to_16(text)) # 先进行aes加密
encrypted_text = str(base64.encodebytes(encrypt_aes), encoding='utf-8')
return encrypted_text
# 解密方法
def decrypt(key, text):
aes = AES.new(add_to_16(key), AES.MODE_ECB) # 初始化加密器
base64_decrypted = base64.decodebytes(text.encode(encoding='utf-8'))
decrypted_text = str(aes.decrypt(base64_decrypted), encoding='utf-8').replace('\0', '') # 执行解密密并转码返回str
return decrypted_text
================================================
FILE: 第三章:Web Js逆向/3.5 常见的编码和加密/3.5.7 RSA/rsa_encrypt.js
================================================
window = global;
const JSEncrypt = require('jsencrypt');
publickey = '公钥';
// 加密
let jse = new JSEncrypt();
jse.setPublicKey(publickey);
var encStr = jse.encrypt('username');
// 解密
privatekey = '私钥';
jse.setPrivateKey(privatekey);
var Str = jse.decrypt(encStr);
================================================
FILE: 第三章:Web Js逆向/3.5 常见的编码和加密/3.5.7 RSA/rsa_encrypt.py
================================================
import base64
import rsa
from rsa import common
class RsaUtil(object):
PUBLIC_KEY_PATH = 'public_key.pem' # 公钥
PRIVATE_KEY_PATH = 'private_key.pem' # 私钥
# 初始化key
def __init__(self,
company_pub_file=PUBLIC_KEY_PATH,
company_pri_file=PRIVATE_KEY_PATH):
if company_pub_file:
self.company_public_key = rsa.PublicKey.load_pkcs1_openssl_pem(open(company_pub_file).read())
if company_pri_file:
self.company_private_key = rsa.PrivateKey.load_pkcs1(open(company_pri_file).read())
def get_max_length(self, rsa_key, encrypt=True):
"""加密内容过长时 需要分段加密 换算每一段的长度.
:param rsa_key: 钥匙.
:param encrypt: 是否是加密.
"""
blocksize = common.byte_size(rsa_key.n)
reserve_size = 11 # 预留位为11
if not encrypt: # 解密时不需要考虑预留位
reserve_size = 0
maxlength = blocksize - reserve_size
return maxlength
def encrypt_by_public_key(self, message):
"""使用公钥加密.
:param message: 需要加密的内容.
加密之后需要对接过进行base64转码
"""
encrypt_result = b''
max_length = self.get_max_length(self.company_public_key)
while message:
input = message[:max_length]
message = message[max_length:]
out = rsa.encrypt(input, self.company_public_key)
encrypt_result += out
encrypt_result = base64.b64encode(encrypt_result)
return encrypt_result
def decrypt_by_private_key(self, message):
"""使用私钥解密.
:param message: 需要加密的内容.
解密之后的内容直接是字符串,不需要在进行转义
"""
decrypt_result = b""
max_length = self.get_max_length(self.company_private_key, False)
decrypt_message = base64.b64decode(message)
while decrypt_message:
input = decrypt_message[:max_length]
decrypt_message = decrypt_message[max_length:]
out = rsa.decrypt(input, self.company_private_key)
decrypt_result += out
return decrypt_result
def sign_by_private_key(self, data):
"""私钥签名.
:param data: 需要签名的内容.
使用SHA-1 方法进行签名(也可以使用MD5)
签名之后,需要转义后输出
"""
signature = rsa.sign(str(data), priv_key=self.company_private_key, hash='SHA-1')
return base64.b64encode(signature)
def verify_by_public_key(self, message, signature):
"""公钥验签.
:param message: 验签的内容.
:param signature: 对验签内容签名的值(签名之后,会进行b64encode转码,所以验签前也需转码).
"""
signature = base64.b64decode(signature)
return rsa.verify(message, signature, self.company_public_key)
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.1 virustotal逆向入门案例/js3.6.1.py
================================================
import execjs
import requests
from lxpy import copy_headers_dict
url = 'https://www.virustotal.com/ui/search?limit=20&relationships%5Bcomment%5D=author%2Citem&query=1'
headers = copy_headers_dict('''
accept: application/json
accept-encoding: gzip, deflate, br
accept-ianguage: en-US,en;q=0.9,es;q=0.8
accept-language: zh-CN,zh;q=0.9
content-type: application/json
cookie: _ga=GA1.2.747208657.1642417044; _gid=GA1.2.988701706.1642417044
referer: https://www.virustotal.com/
sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-origin
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
x-app-version: v1x57x0
x-tool: vt-ui-main
''')
js = '''
function get_anti(){
const e = Date.now() / 1e3;
return Buffer.from((`${(()=>{
const e = 1e10 * (1 + Math.random() % 5e4);
return e < 50 ? "-1" : e.toFixed(0)
}
)()}-ZG9udCBiZSBldmls-${e}`)).toString('base64');
}
'''
xvt_anti = execjs.compile(js).call('get_anti')
headers.update({'x-vt-anti-abuse-header':xvt_anti})
print(requests.get(url, headers=headers).text)
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.2 newrank榜单逆向案例/js3.6.2.py
================================================
import requests
import execjs
class XbRank():
def __init__(self):
self.session=requests.session()
self.headers = {
'accept-language': 'zh-CN,zh;q=0.9',
'origin': 'https://newrank.cn',
'referer': 'https://newrank.cn/public/info/search.html?value=pythonlx&isBind=false',
'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"',
'sec-ch-ua-mobile': '?0',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'cookie': 'UM_distinctid=17e67d04321599-0bb674ea32cd44-f791b31-1fa400-17e67d04322e09; CNZZDATA1253878005=868574852-1642412670-%7C1642412670',
'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',
'x-requested-with': 'XMLHttpRequest',
}
def getxyz(self,path):
js = '''
function nonce() {
for (var a = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"], b = 0; b < 500; b++)
for (var c = "", d = 0; d < 9; d++) {
var e = Math.floor(16 * Math.random());
c += a[e]
}
return c
}
function b(a) {
function b(a) {
return d(c(e(a)))
}
function c(a) {
return g(h(f(a), 8 * a.length))
}
function d(a) {
for (var b, c = p ? "0123456789ABCDEF" : "0123456789abcdef", d = "", e = 0; e < a.length; e++)
b = a.charCodeAt(e),
d += c.charAt(b >>> 4 & 15) + c.charAt(15 & b);
return d
}
function e(a) {
for (var b, c, d = "", e = -1; ++e < a.length; )
b = a.charCodeAt(e),
c = e + 1 < a.length ? a.charCodeAt(e + 1) : 0,
55296 <= b && b <= 56319 && 56320 <= c && c <= 57343 && (b = 65536 + ((1023 & b) << 10) + (1023 & c),
e++),
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));
return d
}
function f(a) {
for (var b = Array(a.length >> 2), c = 0; c < b.length; c++)
b[c] = 0;
for (var c = 0; c < 8 * a.length; c += 8)
b[c >> 5] |= (255 & a.charCodeAt(c / 8)) << c % 32;
return b
}
function g(a) {
for (var b = "", c = 0; c < 32 * a.length; c += 8)
b += String.fromCharCode(a[c >> 5] >>> c % 32 & 255);
return b
}
function h(a, b) {
a[b >> 5] |= 128 << b % 32,
a[14 + (b + 64 >>> 9 << 4)] = b;
for (var c = 1732584193, d = -271733879, e = -1732584194, f = 271733878, g = 0; g < a.length; g += 16) {
var h = c
, i = d
, o = e
, p = f;
c = j(c, d, e, f, a[g + 0], 7, -680876936),
f = j(f, c, d, e, a[g + 1], 12, -389564586),
e = j(e, f, c, d, a[g + 2], 17, 606105819),
d = j(d, e, f, c, a[g + 3], 22, -1044525330),
c = j(c, d, e, f, a[g + 4], 7, -176418897),
f = j(f, c, d, e, a[g + 5], 12, 1200080426),
e = j(e, f, c, d, a[g + 6], 17, -1473231341),
d = j(d, e, f, c, a[g + 7], 22, -45705983),
c = j(c, d, e, f, a[g + 8], 7, 1770035416),
f = j(f, c, d, e, a[g + 9], 12, -1958414417),
e = j(e, f, c, d, a[g + 10], 17, -42063),
d = j(d, e, f, c, a[g + 11], 22, -1990404162),
c = j(c, d, e, f, a[g + 12], 7, 1804603682),
f = j(f, c, d, e, a[g + 13], 12, -40341101),
e = j(e, f, c, d, a[g + 14], 17, -1502002290),
d = j(d, e, f, c, a[g + 15], 22, 1236535329),
c = k(c, d, e, f, a[g + 1], 5, -165796510),
f = k(f, c, d, e, a[g + 6], 9, -1069501632),
e = k(e, f, c, d, a[g + 11], 14, 643717713),
d = k(d, e, f, c, a[g + 0], 20, -373897302),
c = k(c, d, e, f, a[g + 5], 5, -701558691),
f = k(f, c, d, e, a[g + 10], 9, 38016083),
e = k(e, f, c, d, a[g + 15], 14, -660478335),
d = k(d, e, f, c, a[g + 4], 20, -405537848),
c = k(c, d, e, f, a[g + 9], 5, 568446438),
f = k(f, c, d, e, a[g + 14], 9, -1019803690),
e = k(e, f, c, d, a[g + 3], 14, -187363961),
d = k(d, e, f, c, a[g + 8], 20, 1163531501),
c = k(c, d, e, f, a[g + 13], 5, -1444681467),
f = k(f, c, d, e, a[g + 2], 9, -51403784),
e = k(e, f, c, d, a[g + 7], 14, 1735328473),
d = k(d, e, f, c, a[g + 12], 20, -1926607734),
c = l(c, d, e, f, a[g + 5], 4, -378558),
f = l(f, c, d, e, a[g + 8], 11, -2022574463),
e = l(e, f, c, d, a[g + 11], 16, 1839030562),
d = l(d, e, f, c, a[g + 14], 23, -35309556),
c = l(c, d, e, f, a[g + 1], 4, -1530992060),
f = l(f, c, d, e, a[g + 4], 11, 1272893353),
e = l(e, f, c, d, a[g + 7], 16, -155497632),
d = l(d, e, f, c, a[g + 10], 23, -1094730640),
c = l(c, d, e, f, a[g + 13], 4, 681279174),
f = l(f, c, d, e, a[g + 0], 11, -358537222),
e = l(e, f, c, d, a[g + 3], 16, -722521979),
d = l(d, e, f, c, a[g + 6], 23, 76029189),
c = l(c, d, e, f, a[g + 9], 4, -640364487),
f = l(f, c, d, e, a[g + 12], 11, -421815835),
e = l(e, f, c, d, a[g + 15], 16, 530742520),
d = l(d, e, f, c, a[g + 2], 23, -995338651),
c = m(c, d, e, f, a[g + 0], 6, -198630844),
f = m(f, c, d, e, a[g + 7], 10, 1126891415),
e = m(e, f, c, d, a[g + 14], 15, -1416354905),
d = m(d, e, f, c, a[g + 5], 21, -57434055),
c = m(c, d, e, f, a[g + 12], 6, 1700485571),
f = m(f, c, d, e, a[g + 3], 10, -1894986606),
e = m(e, f, c, d, a[g + 10], 15, -1051523),
d = m(d, e, f, c, a[g + 1], 21, -2054922799),
c = m(c, d, e, f, a[g + 8], 6, 1873313359),
f = m(f, c, d, e, a[g + 15], 10, -30611744),
e = m(e, f, c, d, a[g + 6], 15, -1560198380),
d = m(d, e, f, c, a[g + 13], 21, 1309151649),
c = m(c, d, e, f, a[g + 4], 6, -145523070),
f = m(f, c, d, e, a[g + 11], 10, -1120210379),
e = m(e, f, c, d, a[g + 2], 15, 718787259),
d = m(d, e, f, c, a[g + 9], 21, -343485551),
c = n(c, h),
d = n(d, i),
e = n(e, o),
f = n(f, p)
}
return Array(c, d, e, f)
}
function i(a, b, c, d, e, f) {
return n(o(n(n(b, a), n(d, f)), e), c)
}
function j(a, b, c, d, e, f, g) {
return i(b & c | ~b & d, a, b, e, f, g)
}
function k(a, b, c, d, e, f, g) {
return i(b & d | c & ~d, a, b, e, f, g)
}
function l(a, b, c, d, e, f, g) {
return i(b ^ c ^ d, a, b, e, f, g)
}
function m(a, b, c, d, e, f, g) {
return i(c ^ (b | ~d), a, b, e, f, g)
}
function n(a, b) {
var c = (65535 & a) + (65535 & b);
return (a >> 16) + (b >> 16) + (c >> 16) << 16 | 65535 & c
}
function o(a, b) {
return a << b | a >>> 32 - b
}
var p = 0;
return b(a)
}
'''
ctx = execjs.compile(js)
nonce=ctx.eval('nonce()')
path = path.replace('*****',nonce)
xyz=ctx.eval(path)
return nonce,xyz
def getMedia(self,page=1):
""" 获取新榜资讯 """
url = "https://www.newrank.cn/xdnphb/index/getMedia"
path='b("/xdnphb/index/getMedia?AppKey=joker&keyword=&pageNumber={}&pageSize=10&nonce={}")'.format(page,'*****')
nonce, xyz =self.getxyz(path)
data = {
"keyword":"",
"pageNumber": str(page),
"pageSize": "10",
"nonce": nonce,
"xyz": xyz,
}
res=self.session.post(url=url, headers=self.headers, data=data).text
return res
def getRank1(self):
""" 微信-榜单 """
rank_name = '百科'
rank_name_group = '生活'
date = '2022-01-17'
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)
nonce,xyz=self.getxyz(path)
print(nonce,xyz)
getRankUrl = 'https://www.newrank.cn/xdnphb/main/v1/day/rank'
self.data={
"end": date,
"rank_name": rank_name,
"rank_name_group": rank_name_group,
"start": date,
"nonce": nonce,
"xyz": xyz,
}
res=self.session.post(url=getRankUrl,headers=self.headers,data=self.data).json()
return res
def getRank2(self):
""" 视频号-榜单 """
path='b("/xdnphb/data/weixinuser/getMainIndexRank?")'
nonce,xyz=self.getxyz(path)
getUrl = f'https://www.newrank.cn/xdnphb/nr/xinshi/video/getMainIndexRank?nonce={nonce}&xyz={xyz}'
self.data={"interval":"day",
"rank_date":"2021-07-11",
"type":"科技互联网",
"start":1,
"size":50}
res=self.session.post(url=getUrl,headers=self.headers,json=self.data).text
return res
def getRank3(self):
""" 抖音号-榜单 """
getRankUrl = f'https://gw.newrank.cn/api/xd/xdnphb/nr/cloud/douyin/rank/mainHotAccountAllRankList'
self.data={"size":50,"start":1,"type":"才艺","date_type":"days","date":"2021-07-10"}
self.headers.update({'n-token': '9116298d52d64bbfb2bafa92267f74f2'})
res=self.session.post(url=getRankUrl,headers=self.headers,json=self.data).text
return res
def getRank4(self):
""" 快手号-榜单 """
path='b("/xdnphb/nr/cloud/ks/mini/rank/accountAllRankList?")'
nonce,xyz=self.getxyz(path)
getRankUrl = f'https://www.newrank.cn/xdnphb/nr/cloud/ks/mini/rank/accountAllRankList?nonce={nonce}&xyz={xyz}'
self.data={"type":"美食","rankDate":"2021-07-10","start":1,"size":100,"rankType":"realTime","sort":"newrankIndex"}
res=self.session.post(url=getRankUrl,headers=self.headers,json=self.data).text
return res
def getRank5(self):
""" bilibili-榜单 """
path='b("/nr/bili/rank/complexMainRank?")'
nonce,xyz=self.getxyz(path)
getRankUrl = f'https://www.newrank.cn/nr/bili/rank/complexMainRank?nonce={nonce}&xyz={xyz}'
self.data={"numeric":"时尚","rankDate":"2021-07-11","start":1,"size":50,"rankType":"0","type":"0"}
res=self.session.post(url=getRankUrl,headers=self.headers,json=self.data).text
return res
if __name__=="__main__":
xb = XbRank()
print(xb.getRank2())
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.3 MD5加密逆向案例/js3.6.3.py
================================================
from lxpy.encrypt import md5
print(md5.get_md5('11'))
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.4 RSA参数加密逆向案例/js3.6.4.py
================================================
from Cryptodome.PublicKey import RSA
from Cryptodome.Cipher import PKCS1_v1_5
import base64
def encrypt_str(data):
key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsgDq4OqxuEisnk2F0EJFmw4xKa5IrcqEYHvqxPs2CHEg2kolhfWA2SjNuGAHxyDDE5MLtOvzuXjBx/5YJtc9zj2xR/0moesS+Vi/xtG1tkVaTCba+TV+Y5C61iyr3FGqr+KOD4/XECu0Xky1W9ZmmaFADmZi7+6gO9wjgVpU9aLcBcw/loHOeJrCqjp7pA98hRJRY+MML8MK15mnC4ebooOva+mJlstW6t/1lghR8WNV8cocxgcHHuXBxgns2MlACQbSdJ8c6Z3RQeRZBzyjfey6JCCfbEKouVrWIUuPphBL3OANfgp0B+QG31bapvePTfXU48TYK0M5kE+8LgbbWQIDAQAB"
rsakey = RSA.import_key(base64.b64decode(key))
cipher = PKCS1_v1_5.new(rsakey)
cipher_text = base64.b64encode(cipher.encrypt(data.encode(encoding="utf-8")))
return cipher_text
password = encrypt_str("11")
print(password)
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.5 AES数据加密逆向案例/run.py
================================================
import requests
import base64,json,re
from Crypto.Cipher import AES
def decrypt(info: str) -> list:
key = '3sd&d24h@$udD2s*'.encode(encoding='utf-8')
cipher = AES.new(key, mode=AES.MODE_ECB)
json_str = str(cipher.decrypt(base64.b64decode(info)), encoding='utf-8')
data = re.sub('[\x00-\x09|\x0b-\x0c|\x0e-\x1f]', '', json_str)
return json.loads(data)
headers = {}# 需要把你的header复制进去
url = "https://api.hanghangcha.com/hhc/tag" # 产业图谱接口
res = requests.get(url,headers=headers)
payload = json.loads(res.content)['data']
data = decrypt(payload)
print(data)
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.6 AES链接加密逆向案例/js3.6.6/js3.6.6.py
================================================
import execjs
js = '''
// npm install crypto-js
var CryptoJS = require("crypto-js");
function lx(hh) {
var aa = hh.split("/");
var aaa = aa.length;
var bbb = aa[aaa - 1].split('.');
var ccc = bbb[0];
var cccc = bbb[1];
var r = /^\+?[1-9][0-9]*$/;
var srcs = CryptoJS.enc.Utf8.parse(ccc);
var s = "qnbyzzwmdgghmcnm";
var k = CryptoJS.enc.Utf8.parse(s);
var en = CryptoJS.AES.encrypt(srcs, k, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
var ddd = en.toString();
ddd = ddd.replace(/\//g, "^");
ddd = ddd.substring(0, ddd.length - 2);
var bbbb = ddd + '.' + bbb[1];
aa[aaa - 1] = bbbb;
var uuu = '';
for (i = 0; i < aaa; i++) {
uuu += aa[i] + '/'
}
uuu = uuu.substring(0, uuu.length - 1);
return uuu;
}
'''
hh="http://ggzy.zwfwb.tj.gov.cn:80/jyxxcgjg/970369.jhtml"
url = execjs.compile(js).call('lx',hh)
print(url)
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.6 AES链接加密逆向案例/js3.6.6/package.json
================================================
{
"dependencies": {
"crypto-js": "^4.1.1"
}
}
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.6 AES链接加密逆向案例/js3.6.6/test.js
================================================
var CryptoJS = require("crypto-js");
function lx(hh) {
var aa = hh.split("/");
var aaa = aa.length;
var bbb = aa[aaa - 1].split('.');
var ccc = bbb[0];
var cccc = bbb[1];
var r = /^\+?[1-9][0-9]*$/;
var srcs = CryptoJS.enc.Utf8.parse(ccc);
var s = "qnbyzzwmdgghmcnm";
var k = CryptoJS.enc.Utf8.parse(s);
var en = CryptoJS.AES.encrypt(srcs, k, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
var ddd = en.toString();
ddd = ddd.replace(/\//g, "^");
ddd = ddd.substring(0, ddd.length - 2);
var bbbb = ddd + '.' + bbb[1];
aa[aaa - 1] = bbbb;
var uuu = '';
for (i = 0; i < aaa; i++) {
uuu += aa[i] + '/'
}
uuu = uuu.substring(0, uuu.length - 1);
return uuu;
}
var hh="http://ggzy.zwfwb.tj.gov.cn:80/jyxxcgjg/970369.jhtml";
console.log(lx(hh));
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/run.py
================================================
# -*- coding: utf-8 -*-
# @Time : 2021/12/8 10:58
# @IDE :PyCharm
import requests
import re
import execjs
headers = {
# 如果被拦截,把headers补齐
'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'
}
sess = requests.session()
url = 'https://www.cnvd.org.cn/flaw/list.htm'
def start():
r =sess.get(url,headers=headers,verify=False)
text = r.text
cookie = re.search('',text).group(1)
hash = re.search('"ha":"(.*?)",',data).group(1)
# get_cookie_2是执行JS,完整代码请下载
cookie = get_cookie_2(data,hash).split(';')[0].split('=')
sess.cookies[cookie[0]] =cookie[1]
def end(page=1):
data = {'number': '请输入精确编号', 'startDate': '', 'endDate': '', 'field': '', 'order': '', 'numPerPage': '10', 'offset': page*10, 'max': '10'}
r1 = sess.post('https://www.cnvd.org.cn/flaw/list.htm?flag=true',headers=headers,data=data,verify=False)
print(r1.text)
def get_cookie_2(data,hash):
node = execjs.get()
path=f'./t_{hash}.js'
with open(path,'r',encoding='utf-8') as f:
ctx = node.compile(f.read())
funcName = f'go({data})'
pwd = ctx.eval(funcName)
return pwd
if __name__ == '__main__':
start()
then()
end()
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_md5.js
================================================
window = {}
window.navigator={
'userAgent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'
}
function hash(_0x1502a6) {
function _0x4a30e6(_0x2ea6d4, _0x522caa) {
return _0x2ea6d4 << _0x522caa | _0x2ea6d4 >>> 32 - _0x522caa;
}
function _0x310ed6(_0x28f8be, _0x1b6c23) {
var _0x2cdaf, _0x5e54a4, _0x101c95, _0x1dd704, _0x5788f8;
_0x101c95 = _0x28f8be & 2147483648;
_0x1dd704 = _0x1b6c23 & 2147483648;
_0x2cdaf = _0x28f8be & 1073741824;
_0x5e54a4 = _0x1b6c23 & 1073741824;
_0x5788f8 = (_0x28f8be & 1073741823) + (_0x1b6c23 & 1073741823);
if (_0x2cdaf & _0x5e54a4) {
return _0x5788f8 ^ 2147483648 ^ _0x101c95 ^ _0x1dd704;
}
if (_0x2cdaf | _0x5e54a4) {
if (_0x5788f8 & 1073741824) {
return _0x5788f8 ^ 3221225472 ^ _0x101c95 ^ _0x1dd704;
} else {
return _0x5788f8 ^ 1073741824 ^ _0x101c95 ^ _0x1dd704;
}
} else {
return _0x5788f8 ^ _0x101c95 ^ _0x1dd704;
}
}
function _0x46d0b1(_0x3b37cc, _0x341375, _0x2fc6de) {
return _0x3b37cc & _0x341375 | ~_0x3b37cc & _0x2fc6de;
}
function _0xd50fd1(_0x47204c, _0x1dc758, _0x44c0fb) {
return _0x47204c & _0x44c0fb | _0x1dc758 & ~_0x44c0fb;
}
function _0x35b4c6(_0x477c88, _0x4dc0bf, _0x352ef4) {
return _0x477c88 ^ _0x4dc0bf ^ _0x352ef4;
}
function _0x556522(_0x356dac, _0x1b0899, _0x9fcb5b) {
return _0x1b0899 ^ (_0x356dac | ~_0x9fcb5b);
}
function _0x28c82a(_0x29ad55, _0x9d146f, _0xefb3b1, _0x5971fb, _0x4d05c0, _0x534b3e, _0x17d415) {
_0x29ad55 = _0x310ed6(_0x29ad55, _0x310ed6(_0x310ed6(_0x46d0b1(_0x9d146f, _0xefb3b1, _0x5971fb), _0x4d05c0), _0x17d415));
return _0x310ed6(_0x4a30e6(_0x29ad55, _0x534b3e), _0x9d146f);
}
function _0x6a1761(_0xadedd3, _0x4676b4, _0x3e62e4, _0x3c2512, _0x659e9e, _0x21f4da, _0x3e0c76) {
_0xadedd3 = _0x310ed6(_0xadedd3, _0x310ed6(_0x310ed6(_0xd50fd1(_0x4676b4, _0x3e62e4, _0x3c2512), _0x659e9e), _0x3e0c76));
return _0x310ed6(_0x4a30e6(_0xadedd3, _0x21f4da), _0x4676b4);
}
function _0x2a4a91(_0x4b4638, _0x472a89, _0x5e4e16, _0x3888b2, _0x4e74dc, _0x316a7d, _0x4cf99a) {
_0x4b4638 = _0x310ed6(_0x4b4638, _0x310ed6(_0x310ed6(_0x35b4c6(_0x472a89, _0x5e4e16, _0x3888b2), _0x4e74dc), _0x4cf99a));
return _0x310ed6(_0x4a30e6(_0x4b4638, _0x316a7d), _0x472a89);
}
function _0x3b9fc8(_0x4c16ec, _0x3aa156, _0x4d0799, _0x573d5f, _0x533c36, _0x663a85, _0x27414f) {
_0x4c16ec = _0x310ed6(_0x4c16ec, _0x310ed6(_0x310ed6(_0x556522(_0x3aa156, _0x4d0799, _0x573d5f), _0x533c36), _0x27414f));
return _0x310ed6(_0x4a30e6(_0x4c16ec, _0x663a85), _0x3aa156);
}
function _0x2fed37(_0x516a09) {
var _0x599f7b;
var _0x1b4436 = _0x516a09["length"];
var _0x427f94 = _0x1b4436 + 8;
var _0x5c1538 = (_0x427f94 - _0x427f94 % 64) / 64;
var _0x4a4a84 = (_0x5c1538 + 1) * 16;
var _0xfd255a = Array(_0x4a4a84 - 1);
var _0x37d2af = 0;
var _0x199862 = 0;
while (_0x199862 < _0x1b4436) {
_0x599f7b = (_0x199862 - _0x199862 % 4) / 4;
_0x37d2af = _0x199862 % 4 * 8;
_0xfd255a[_0x599f7b] = _0xfd255a[_0x599f7b] | _0x516a09["charCodeAt"](_0x199862) << _0x37d2af;
_0x199862++;
}
_0x599f7b = (_0x199862 - _0x199862 % 4) / 4;
_0x37d2af = _0x199862 % 4 * 8;
_0xfd255a[_0x599f7b] = _0xfd255a[_0x599f7b] | 128 << _0x37d2af;
_0xfd255a[_0x4a4a84 - 2] = _0x1b4436 << 3;
_0xfd255a[_0x4a4a84 - 1] = _0x1b4436 >>> 29;
return _0xfd255a;
}
function _0xe68e4a(_0x4eb6f7) {
var _0x45b2c8 = "",
_0x393ae1 = "",
_0x1e16e0,
_0x30b994;
for (_0x30b994 = 0; _0x30b994 <= 3; _0x30b994++) {
_0x1e16e0 = _0x4eb6f7 >>> _0x30b994 * 8 & 255;
_0x393ae1 = "0" + _0x1e16e0["toString"](16);
_0x45b2c8 = _0x45b2c8 + _0x393ae1["substr"](_0x393ae1["length"] - 2, 2);
}
return _0x45b2c8;
}
var _0x36cde0 = Array();
var _0x47a255, _0x1a5c2a, _0xecb31, _0x4d24cf, _0x49db35, _0x1df490, _0x556813, _0x5dc91d, _0x14adb7;
var _0x24af54 = 7,
_0x5a822b = 12,
_0x3bfc54 = 17,
_0x3f8aea = 22;
var _0x3738d3 = 5,
_0x4324e8 = 9,
_0x230e41 = 14,
_0x4286f0 = 20;
var _0x470748 = 4,
_0x5525e3 = 11,
_0x34b532 = 16,
_0xc1dd6 = 23;
var _0x26a2d5 = 6,
_0x5ad210 = 10,
_0x509fcc = 15,
_0x20edf6 = 21;
_0x36cde0 = _0x2fed37(_0x1502a6);
_0x1df490 = 1732584193;
_0x556813 = 4023233417;
_0x5dc91d = 2562383102;
_0x14adb7 = 271733878;
for (_0x47a255 = 0; _0x47a255 < _0x36cde0["length"]; _0x47a255 += 16) {
_0x1a5c2a = _0x1df490;
_0xecb31 = _0x556813;
_0x4d24cf = _0x5dc91d;
_0x49db35 = _0x14adb7;
_0x1df490 = _0x28c82a(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 0], _0x24af54, 3614090360);
_0x14adb7 = _0x28c82a(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 1], _0x5a822b, 3905402710);
_0x5dc91d = _0x28c82a(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 2], _0x3bfc54, 606105819);
_0x556813 = _0x28c82a(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 3], _0x3f8aea, 3250441966);
_0x1df490 = _0x28c82a(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 4], _0x24af54, 4118548399);
_0x14adb7 = _0x28c82a(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 5], _0x5a822b, 1200080426);
_0x5dc91d = _0x28c82a(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 6], _0x3bfc54, 2821735955);
_0x556813 = _0x28c82a(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 7], _0x3f8aea, 4249261313);
_0x1df490 = _0x28c82a(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 8], _0x24af54, 1770035416);
_0x14adb7 = _0x28c82a(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 9], _0x5a822b, 2336552879);
_0x5dc91d = _0x28c82a(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 10], _0x3bfc54, 4294925233);
_0x556813 = _0x28c82a(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 11], _0x3f8aea, 2304563134);
_0x1df490 = _0x28c82a(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 12], _0x24af54, 1804603682);
_0x14adb7 = _0x28c82a(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 13], _0x5a822b, 4254626195);
_0x5dc91d = _0x28c82a(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 14], _0x3bfc54, 2792965006);
_0x556813 = _0x28c82a(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 15], _0x3f8aea, 1236535329);
_0x1df490 = _0x6a1761(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 1], _0x3738d3, 4129170786);
_0x14adb7 = _0x6a1761(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 6], _0x4324e8, 3225465664);
_0x5dc91d = _0x6a1761(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 11], _0x230e41, 643717713);
_0x556813 = _0x6a1761(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 0], _0x4286f0, 3921069994);
_0x1df490 = _0x6a1761(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 5], _0x3738d3, 3593408605);
_0x14adb7 = _0x6a1761(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 10], _0x4324e8, 38016083);
_0x5dc91d = _0x6a1761(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 15], _0x230e41, 3634488961);
_0x556813 = _0x6a1761(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 4], _0x4286f0, 3889429448);
_0x1df490 = _0x6a1761(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 9], _0x3738d3, 568446438);
_0x14adb7 = _0x6a1761(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 14], _0x4324e8, 3275163606);
_0x5dc91d = _0x6a1761(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 3], _0x230e41, 4107603335);
_0x556813 = _0x6a1761(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 8], _0x4286f0, 1163531501);
_0x1df490 = _0x6a1761(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 13], _0x3738d3, 2850285829);
_0x14adb7 = _0x6a1761(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 2], _0x4324e8, 4243563512);
_0x5dc91d = _0x6a1761(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 7], _0x230e41, 1735328473);
_0x556813 = _0x6a1761(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 12], _0x4286f0, 2368359562);
_0x1df490 = _0x2a4a91(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 5], _0x470748, 4294588738);
_0x14adb7 = _0x2a4a91(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 8], _0x5525e3, 2272392833);
_0x5dc91d = _0x2a4a91(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 11], _0x34b532, 1839030562);
_0x556813 = _0x2a4a91(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 14], _0xc1dd6, 4259657740);
_0x1df490 = _0x2a4a91(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 1], _0x470748, 2763975236);
_0x14adb7 = _0x2a4a91(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 4], _0x5525e3, 1272893353);
_0x5dc91d = _0x2a4a91(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 7], _0x34b532, 4139469664);
_0x556813 = _0x2a4a91(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 10], _0xc1dd6, 3200236656);
_0x1df490 = _0x2a4a91(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 13], _0x470748, 681279174);
_0x14adb7 = _0x2a4a91(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 0], _0x5525e3, 3936430074);
_0x5dc91d = _0x2a4a91(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 3], _0x34b532, 3572445317);
_0x556813 = _0x2a4a91(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 6], _0xc1dd6, 76029189);
_0x1df490 = _0x2a4a91(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 9], _0x470748, 3654602809);
_0x14adb7 = _0x2a4a91(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 12], _0x5525e3, 3873151461);
_0x5dc91d = _0x2a4a91(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 15], _0x34b532, 530742520);
_0x556813 = _0x2a4a91(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 2], _0xc1dd6, 3299628645);
_0x1df490 = _0x3b9fc8(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 0], _0x26a2d5, 4096336452);
_0x14adb7 = _0x3b9fc8(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 7], _0x5ad210, 1126891415);
_0x5dc91d = _0x3b9fc8(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 14], _0x509fcc, 2878612391);
_0x556813 = _0x3b9fc8(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 5], _0x20edf6, 4237533241);
_0x1df490 = _0x3b9fc8(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 12], _0x26a2d5, 1700485571);
_0x14adb7 = _0x3b9fc8(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 3], _0x5ad210, 2399980690);
_0x5dc91d = _0x3b9fc8(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 10], _0x509fcc, 4293915773);
_0x556813 = _0x3b9fc8(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 1], _0x20edf6, 2240044497);
_0x1df490 = _0x3b9fc8(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 8], _0x26a2d5, 1873313359);
_0x14adb7 = _0x3b9fc8(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 15], _0x5ad210, 4264355552);
_0x5dc91d = _0x3b9fc8(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 6], _0x509fcc, 2734768916);
_0x556813 = _0x3b9fc8(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 13], _0x20edf6, 1309151649);
_0x1df490 = _0x3b9fc8(_0x1df490, _0x556813, _0x5dc91d, _0x14adb7, _0x36cde0[_0x47a255 + 4], _0x26a2d5, 4149444226);
_0x14adb7 = _0x3b9fc8(_0x14adb7, _0x1df490, _0x556813, _0x5dc91d, _0x36cde0[_0x47a255 + 11], _0x5ad210, 3174756917);
_0x5dc91d = _0x3b9fc8(_0x5dc91d, _0x14adb7, _0x1df490, _0x556813, _0x36cde0[_0x47a255 + 2], _0x509fcc, 718787259);
_0x556813 = _0x3b9fc8(_0x556813, _0x5dc91d, _0x14adb7, _0x1df490, _0x36cde0[_0x47a255 + 9], _0x20edf6, 3951481745);
_0x1df490 = _0x310ed6(_0x1df490, _0x1a5c2a);
_0x556813 = _0x310ed6(_0x556813, _0xecb31);
_0x5dc91d = _0x310ed6(_0x5dc91d, _0x4d24cf);
_0x14adb7 = _0x310ed6(_0x14adb7, _0x49db35);
}
var _0x1b2afe = _0xe68e4a(_0x1df490) + _0xe68e4a(_0x556813) + _0xe68e4a(_0x5dc91d) + _0xe68e4a(_0x14adb7);
return _0x1b2afe["toLowerCase"]();
}
function go(_0x3dcb2b) {
function _0x3176b1() {
var _0x4ed7b4 = window["navigator"]["userAgent"],
_0x4f1f22 = ["Phantom"];
for (var _0xe1d6a1 = 0; _0xe1d6a1 < _0x4f1f22["length"]; _0xe1d6a1++) {
if (_0x4ed7b4["indexOf"](_0x4f1f22[_0xe1d6a1]) != -1) {
return true;
}
}
if (window["callPhantom"] || window["_phantom"] || window["Headless"] || window["navigator"]["webdriver"] || window["navigator"]["__driver_evaluate"] || window["navigator"]["__webdriver_evaluate"]) {
return true;
}
}
if (_0x3176b1()) {
return;
}
var _0xd2394e = new Date();
function _0xf762a5(_0xc5acfd, _0x2a3cc5) {
var _0x134453 = _0x3dcb2b["chars"]["length"];
for (var _0x9d4cd5 = 0; _0x9d4cd5 < _0x134453; _0x9d4cd5++) {
for (var _0x40802b = 0; _0x40802b < _0x134453; _0x40802b++) {
var _0x31753d = _0x2a3cc5[0] + _0x3dcb2b["chars"]["substr"](_0x9d4cd5, 1) + _0x3dcb2b["chars"]["substr"](_0x40802b, 1) + _0x2a3cc5[1];
if (hash(_0x31753d) == _0xc5acfd) {
return [_0x31753d, new Date() - _0xd2394e];
}
}
}
}
var _0x4d8b5f = _0xf762a5(_0x3dcb2b["ct"], _0x3dcb2b["bts"]);
if (_0x4d8b5f) {
var _0x531b56;
if (_0x3dcb2b["wt"]) {
_0x531b56 = parseInt(_0x3dcb2b["wt"]) > _0x4d8b5f[1] ? parseInt(_0x3dcb2b["wt"]) - _0x4d8b5f[1] : 500;
} else {
_0x531b56 = 1500;
}
let c= _0x3dcb2b["tn"] + "=" + _0x4d8b5f[0] + ";Max-age=" + _0x3dcb2b["vt"] + "; path = /";
console.log(c);
return c
} else {
alert("\u8BF7\u6C42\u9A8C\u8BC1\xE5\xA4\xB1\xE8\xB4\xA5");
}
}
go({
"bts": ["1628087072.474|0|W1w", "wx0d3OdXraK9vfHU8Ub82M%3D"],
"chars": "VWCQTYxwjInsvsInUJsKMX",
"ct": "d2f22b3c4d6fa52cd2483003c121de68",
"ha": "md5",
"tn": "__jsl_clearance_s",
"vt": "3600",
"wt": "1500"
});
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_sha1.js
================================================
window = {}
window.navigator={
'userAgent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'
}
function hash(_0x3cb311) {
function _0x163c9c(_0x46ff88, _0x5150cb) {
return (_0x46ff88 & 2147483647) + (_0x5150cb & 2147483647) ^ _0x46ff88 & 2147483648 ^ _0x5150cb & 2147483648;
}
function _0x26ec8d(_0x3d80d1) {
var _0x4e7763 = "0123456789abcdef";
var _0x1603cb = "";
for (var _0x4a1d1d = 7; _0x4a1d1d >= 0; _0x4a1d1d--) {
_0x1603cb += _0x4e7763["charAt"](_0x3d80d1 >> _0x4a1d1d * 4 & 15);
}
return _0x1603cb;
}
function _0x153602(_0x2c0782) {
var _0x1cd5a1 = (_0x2c0782["length"] + 8 >> 6) + 1,
_0x1db977 = new Array(_0x1cd5a1 * 16);
for (var _0x17fd51 = 0; _0x17fd51 < _0x1cd5a1 * 16; _0x17fd51++) {
_0x1db977[_0x17fd51] = 0;
}
for (_0x17fd51 = 0; _0x17fd51 < _0x2c0782["length"]; _0x17fd51++) {
_0x1db977[_0x17fd51 >> 2] |= _0x2c0782["charCodeAt"](_0x17fd51) << 24 - (_0x17fd51 & 3) * 8;
}
_0x1db977[_0x17fd51 >> 2] |= 128 << 24 - (_0x17fd51 & 3) * 8;
_0x1db977[_0x1cd5a1 * 16 - 1] = _0x2c0782["length"] * 8;
return _0x1db977;
}
function _0x37aa8c(_0x1b0f9a, _0x48e60d) {
return _0x1b0f9a << _0x48e60d | _0x1b0f9a >>> 32 - _0x48e60d;
}
function _0x3ba558(_0x3e8bd0, _0x360d42, _0x2cf1fe, _0x2d6f7f) {
if (_0x3e8bd0 < 20) {
return _0x360d42 & _0x2cf1fe | ~_0x360d42 & _0x2d6f7f;
}
if (_0x3e8bd0 < 40) {
return _0x360d42 ^ _0x2cf1fe ^ _0x2d6f7f;
}
if (_0x3e8bd0 < 60) {
return _0x360d42 & _0x2cf1fe | _0x360d42 & _0x2d6f7f | _0x2cf1fe & _0x2d6f7f;
}
return _0x360d42 ^ _0x2cf1fe ^ _0x2d6f7f;
}
function _0x23a48b(_0x3f81a0) {
return _0x3f81a0 < 20 ? 1518500249 : _0x3f81a0 < 40 ? 1859775393 : _0x3f81a0 < 60 ? -1894007588 : -899497514;
}
var _0x1cdcad = _0x153602(_0x3cb311);
var _0x32dc39 = new Array(80);
var _0xccaec7 = 1732584193;
var _0x32e008 = -271733879;
var _0x485153 = -1732584194;
var _0x489b5b = 271733878;
var _0x205716 = -1009589776;
for (var _0x41a7c6 = 0; _0x41a7c6 < _0x1cdcad["length"]; _0x41a7c6 += 16) {
var _0x152b2d = _0xccaec7;
var _0x1cd17d = _0x32e008;
var _0xf419f9 = _0x485153;
var _0x536541 = _0x489b5b;
var _0x34be50 = _0x205716;
for (var _0x6d61ab = 0; _0x6d61ab < 80; _0x6d61ab++) {
if (_0x6d61ab < 16) {
_0x32dc39[_0x6d61ab] = _0x1cdcad[_0x41a7c6 + _0x6d61ab];
} else {
_0x32dc39[_0x6d61ab] = _0x37aa8c(_0x32dc39[_0x6d61ab - 3] ^ _0x32dc39[_0x6d61ab - 8] ^ _0x32dc39[_0x6d61ab - 14] ^ _0x32dc39[_0x6d61ab - 16], 1);
}
t = _0x163c9c(_0x163c9c(_0x37aa8c(_0xccaec7, 5), _0x3ba558(_0x6d61ab, _0x32e008, _0x485153, _0x489b5b)), _0x163c9c(_0x163c9c(_0x205716, _0x32dc39[_0x6d61ab]), _0x23a48b(_0x6d61ab)));
_0x205716 = _0x489b5b;
_0x489b5b = _0x485153;
_0x485153 = _0x37aa8c(_0x32e008, 30);
_0x32e008 = _0xccaec7;
_0xccaec7 = t;
}
_0xccaec7 = _0x163c9c(_0xccaec7, _0x152b2d);
_0x32e008 = _0x163c9c(_0x32e008, _0x1cd17d);
_0x485153 = _0x163c9c(_0x485153, _0xf419f9);
_0x489b5b = _0x163c9c(_0x489b5b, _0x536541);
_0x205716 = _0x163c9c(_0x205716, _0x34be50);
}
return _0x26ec8d(_0xccaec7) + _0x26ec8d(_0x32e008) + _0x26ec8d(_0x485153) + _0x26ec8d(_0x489b5b) + _0x26ec8d(_0x205716);
}
function go(_0x3643f0) {
function _0x939e9d() {
var _0x25184e = window["navigator"]["userAgent"],
_0x3d9896 = ["Phantom"];
for (var _0x41f164 = 0; _0x41f164 < _0x3d9896["length"]; _0x41f164++) {
if (_0x25184e["indexOf"](_0x3d9896[_0x41f164]) != -1) {
return true;
}
}
if (window["callPhantom"] || window["_phantom"] || window["Headless"] || window["navigator"]["webdriver"] || window["navigator"]["__driver_evaluate"] || window["navigator"]["__webdriver_evaluate"]) {
return true;
}
}
if (_0x939e9d()) {
return;
}
var _0x4a8c9f = new Date();
function _0x30c06b(_0x56f5b0, _0x447494) {
var _0x59337c = _0x3643f0["chars"]["length"];
for (var _0x197671 = 0; _0x197671 < _0x59337c; _0x197671++) {
for (var _0x47ac04 = 0; _0x47ac04 < _0x59337c; _0x47ac04++) {
var _0x357062 = _0x447494[0] + _0x3643f0["chars"]["substr"](_0x197671, 1) + _0x3643f0["chars"]["substr"](_0x47ac04, 1) + _0x447494[1];
if (hash(_0x357062) == _0x56f5b0) {
return [_0x357062, new Date() - _0x4a8c9f];
}
}
}
}
var _0x4f0d12 = _0x30c06b(_0x3643f0["ct"], _0x3643f0["bts"]);
if (_0x4f0d12) {
var _0x1dae31;
if (_0x3643f0["wt"]) {
_0x1dae31 = parseInt(_0x3643f0["wt"]) > _0x4f0d12[1] ? parseInt(_0x3643f0["wt"]) - _0x4f0d12[1] : 500;
} else {
_0x1dae31 = 1500;
}
let c = _0x3643f0["tn"] + "=" + _0x4f0d12[0] + ";Max-age=" + _0x3643f0["vt"] + "; path = /";
console.log(c);
return c
} else {
alert("\u8BF7\u6C42\u9A8C\u8BC1\xE5\xA4\xB1\xE8\xB4\xA5");
}
}
go({
"bts": ["1628088065.4|0|rZGRv", "gwlQ6aBQ9ZCDZeup2IEk%3D"],
"chars": "vMJCKTooRTjlkttqnCeuEL",
"ct": "db970e51a07226e63edcf9153c748160de4a3622",
"ha": "sha1",
"tn": "__jsl_clearance_s",
"vt": "3600",
"wt": "1500"
});
================================================
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_sha256.js
================================================
window = {}
window.navigator={
'userAgent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36'
}
function hash(_0xb3a2f3) {
var _0x436214 = 8;
var _0x3ebd36 = 0;
function _0x70fb8(_0x3b1fbb, _0x4a616c) {
var _0x5df8da = (_0x3b1fbb & 65535) + (_0x4a616c & 65535);
var _0x23a7a2 = (_0x3b1fbb >> 16) + (_0x4a616c >> 16) + (_0x5df8da >> 16);
return _0x23a7a2 << 16 | _0x5df8da & 65535;
}
function _0x4e57dd(_0x4d810e, _0x184aac) {
return _0x4d810e >>> _0x184aac | _0x4d810e << 32 - _0x184aac;
}
function _0x36087b(_0x152685, _0x48a182) {
return _0x152685 >>> _0x48a182;
}
function _0x399548(_0x4dcebb, _0xab0153, _0x7dbf5b) {
return _0x4dcebb & _0xab0153 ^ ~_0x4dcebb & _0x7dbf5b;
}
function _0x48ee3a(_0x333fa7, _0x55d2ec, _0x17a443) {
return _0x333fa7 & _0x55d2ec ^ _0x333fa7 & _0x17a443 ^ _0x55d2ec & _0x17a443;
}
function _0x310842(_0x2be1b1) {
return _0x4e57dd(_0x2be1b1, 2) ^ _0x4e57dd(_0x2be1b1, 13) ^ _0x4e57dd(_0x2be1b1, 22);
}
function _0x7d5a12(_0x647765) {
return _0x4e57dd(_0x647765, 6) ^ _0x4e57dd(_0x647765, 11) ^ _0x4e57dd(_0x647765, 25);
}
function _0x1cdddc(_0x8ec478) {
return _0x4e57dd(_0x8ec478, 7) ^ _0x4e57dd(_0x8ec478, 18) ^ _0x36087b(_0x8ec478, 3);
}
function _0x38e736(_0x57bc8e) {
return _0x4e57dd(_0x57bc8e, 17) ^ _0x4e57dd(_0x57bc8e, 19) ^ _0x36087b(_0x57bc8e, 10);
}
function _0x58103a(_0x3b9164, _0x1e15fd) {
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);
var _0x429abc = new Array(1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225);
var _0x2b18db = new Array(64);
var _0x57b507, _0x2f7eb6, _0x3a62a0, _0x38f7e0, _0x880a21, _0x5a6598, _0xa6d654, _0x3f0a05, _0x1f3b08, _0x521f34;
var _0x4bc8b6, _0x394ae6;
_0x3b9164[_0x1e15fd >> 5] |= 128 << 24 - _0x1e15fd % 32;
_0x3b9164[(_0x1e15fd + 64 >> 9 << 4) + 15] = _0x1e15fd;
for (var _0x1f3b08 = 0; _0x1f3b08 < _0x3b9164["length"]; _0x1f3b08 += 16) {
_0x57b507 = _0x429abc[0];
_0x2f7eb6 = _0x429abc[1];
_0x3a62a0 = _0x429abc[2];
_0x38f7e0 = _0x429abc[3];
_0x880a21 = _0x429abc[4];
_0x5a6598 = _0x429abc[5];
_0xa6d654 = _0x429abc[6];
_0x3f0a05 = _0x429abc[7];
for (var _0x521f34 = 0; _0x521f34 < 64; _0x521f34++) {
if (_0x521f34 < 16) {
_0x2b18db[_0x521f34] = _0x3b9164[_0x521f34 + _0x1f3b08];
} else {
_0x2b18db[_0x521f34] = _0x70fb8(_0x70fb8(_0x70fb8(_0x38e736(_0x2b18db[_0x521f34 - 2]), _0x2b18db[_0x521f34 - 7]), _0x1cdddc(_0x2b18db[_0x521f34 - 15])), _0x2b18db[_0x521f34 - 16]);
}
_0x4bc8b6 = _0x70fb8(_0x70fb8(_0x70fb8(_0x70fb8(_0x3f0a05, _0x7d5a12(_0x880a21)), _0x399548(_0x880a21, _0x5a6598, _0xa6d654)), _0xea397a[_0x521f34]), _0x2b18db[_0x521f34]);
_0x394ae6 = _0x70fb8(_0x310842(_0x57b507), _0x48ee3a(_0x57b507, _0x2f7eb6, _0x3a62a0));
_0x3f0a05 = _0xa6d654;
_0xa6d654 = _0x5a6598;
_0x5a6598 = _0x880a21;
_0x880a21 = _0x70fb8(_0x38f7e0, _0x4bc8b6);
_0x38f7e0 = _0x3a62a0;
_0x3a62a0 = _0x2f7eb6;
_0x2f7eb6 = _0x57b507;
_0x57b507 = _0x70fb8(_0x4bc8b6, _0x394ae6);
}
_0x429abc[0] = _0x70fb8(_0x57b507, _0x429abc[0]);
_0x429abc[1] = _0x70fb8(_0x2f7eb6, _0x429abc[1]);
_0x429abc[2] = _0x70fb8(_0x3a62a0, _0x429abc[2]);
_0x429abc[3] = _0x70fb8(_0x38f7e0, _0x429abc[3]);
_0x429abc[4] = _0x70fb8(_0x880a21, _0x429abc[4]);
_0x429abc[5] = _0x70fb8(_0x5a6598, _0x429abc[5]);
_0x429abc[6] = _0x70fb8(_0xa6d654, _0x429abc[6]);
_0x429abc[7] = _0x70fb8(_0x3f0a05, _0x429abc[7]);
}
return _0x429abc;
}
function _0xe1c49c(_0x1f224c) {
var _0xb5927 = Array();
var _0xc3530a = 255;
for (var _0x1c5849 = 0; _0x1c5849 < _0x1f224c["length"] * _0x436214; _0x1c5849 += _0x436214) {
_0xb5927[_0x1c5849 >> 5] |= (_0x1f224c["charCodeAt"](_0x1c5849 / _0x436214) & _0xc3530a) << 24 - _0x1c5849 % 32;
}
return _0xb5927;
}
function _0x4756fb(_0x57f4af) {
var _0x1d8407 = new RegExp("\n", "g");
_0x57f4af = _0x57f4af["replace"](_0x1d8407, "\n");
var _0x577056 = "";
for (var _0x2ed237 = 0; _0x2ed237 < _0x57f4af["length"]; _0x2ed237++) {
var _0x6189ac = _0x57f4af["charCodeAt"](_0x2ed237);
if (_0x6189ac < 128) {
_0x577056 += String["fromCharCode"](_0x6189ac);
} else {
if (_0x6189ac > 127 && _0x6189ac < 2048) {
_0x577056 += String["fromCharCode"](_0x6189ac >> 6 | 192);
_0x577056 += String["fromCharCode"](_0x6189ac & 63 | 128);
} else {
_0x577056 += String["fromCharCode"](_0x6189ac >> 12 | 224);
_0x577056 += String["fromCharCode"](_0x6189ac >> 6 & 63 | 128);
_0x577056 += String["fromCharCode"](_0x6189ac & 63 | 128);
}
}
}
return _0x577056;
}
function _0x37f0cd(_0x536fde) {
var _0x57d084 = "0123456789abcdef";
var _0x5f16c6 = "";
for (var _0x39c170 = 0; _0x39c170 < _0x536fde["length"] * 4; _0x39c170++) {
_0x5f16c6 += _0x57d084["charAt"](_0x536fde[_0x39c170 >> 2] >> (3 - _0x39c170 % 4) * 8 + 4 & 15) + _0x57d084["charAt"](_0x536fde[_0x39c170 >> 2] >> (3 - _0x39c170 % 4) * 8 & 15);
}
return _0x5f16c6;
}
_0xb3a2f3 = _0x4756fb(_0xb3a2f3);
return _0x37f0cd(_0x58103a(_0xe1c49c(_0xb3a2f3), _0xb3a2f3["length"] * _0x436214));
}
function go(_0x50cd53) {
function _0x42fc6c() {
var _0x20ef9d = window["navigator"]["userAgent"],
_0x54abc6 = ["Phantom"];
for (var _0x27b17f = 0; _0x27b17f < _0x54abc6["length"]; _0x27b17f++) {
if (_0x20ef9d["indexOf"](_0x54abc6[_0x27b17f]) != -1) {
return true;
}
}
if (window["callPhantom"] || window["_phantom"] || window["Headless"] || window["navigator"]["webdriver"] || window["navigator"]["__driver_evaluate"] || window["navigator"]["__webdriver_evaluate"]) {
return true;
}
}
if (_0x42fc6c()) {
return;
}
var _0x171728 = new Date();
function _0x107d5a(_0x3569e5, _0x3a4385) {
var _0x26d368 = _0x50cd53["chars"]["length"];
for (var _0x2f27d0 = 0; _0x2f27d0 < _0x26d368; _0x2f27d0++) {
for (var _0x2726ec = 0; _0x2726ec < _0x26d368; _0x2726ec++) {
var _0x58eac9 = _0x3a4385[0] + _0x50cd53["chars"]["substr"](_0x2f27d0, 1) + _0x50cd53["chars"]["substr"](_0x2726ec, 1) + _0x3a4385[1];
if (hash(_0x58eac9) == _0x3569e5) {
return [_0x58eac9, new Date() - _0x171728];
}
}
}
}
var _0x454576 = _0x107d5a(_0x50cd53["ct"], _0x50cd53["bts"]);
if (_0x454576) {
var _0x3fef91;
if (_0x50cd53["wt"]) {
_0x3fef91 = parseInt(_0x50cd53["wt"]) > _0x454576[1] ? parseInt(_0x50cd53["wt"]) - _0x454576[1] : 500;
} else {
_0x3fef91 = 1500;
}
let c = _0x50cd53["tn"] + "=" + _0x454576[0] + ";Max-age=" + _0x50cd53["vt"] + "; path = /";
return c;
} else {
alert("\u8BF7\u6C42\u9A8C\u8BC1\xE5\xA4\xB1\xE8\xB4\xA5");
}
}
console.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"}
));
================================================
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/js-hook.txt
================================================
## Hook setInterval
```js
let _setInterval=setInterval;
setInterval=function(a,b){
if(a.toString().indexOf("debugger")!=-1){
return null;
}
_setInterval(a,b);
}
```
## Hook Cookie Info
```js
var cookie_cache = document.cookie;
Object.defineProperty(document, 'cookie', {
get: function() {
console.log('Getting cookie');
return cookie_cache;
},
set: function(val) {
console.log('Setting cookie', val);
var cookie = val.split(";")[0];
var ncookie = cookie.split("=");
var flag = false;
var cache = cookie_cache.split("; ");
cache = cache.map(function(a){
if (a.split("=")[0] === ncookie[0]){
flag = true;
return cookie;
}
return a;
})
cookie_cache = cache.join("; ");
if (!flag){
cookie_cache += cookie + "; ";
}
this._value = val;
return cookie_cache;
},
});
```
## Hook Json Info
```js
var my_stringify = JSON.stringify;
JSON.stringify = function (params){
console.log("json_stringify:", params);
return json_stringify(params);
};
var my_parse = JSON.parse;
JSON.parse = function (params){
console.log("json_parse:", params);
return json_parse(params);
};
```
## Hook WebSocket
```js
WebSocket.prototype.senda = WebSocket.prototype.send;
WebSocket.prototype.send = function (data){
console.info("Hook WebSocket", data);
return this.senda(data)
}
```
================================================
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/readme.md
================================================
常被检测的环境中,有windows、location、navigate、document、native、canvas等。
除了这些属性外,还有针对于自动化的检测、node环境的检测、以及浏览器指纹检测、TLS指纹校验等。
所谓的补环境是指在Node环境中去运行浏览器的代码,因为Node环境和浏览器环境是不同的,比如DOM渲染和浏览器内置方法,而经常需要补的内容也是这些。
笔者总结的补环境有两种方式,一是在本地Node中扣代码补环境,二是通过驱动开启一个浏览器环境去执行代码,但是需要记得补驱动的特征。
不过最优的方法还是在本地补,所以这里简单分享一些补的方法和代码。
---
3.7.0 中给出的几个文件是笔者准备的一些工具类,笔者自己写的和收集于网络的都贴上来。
由于这块内容不太好总结,环境并不是通用的。用文字来描述的话,要么贴已经补过的代码,要么贴一键hook的脚本。
虽然每次补之前直接把各种环境堆上去碰运气也是一种方法,但是碰到独特的检测点等于直接从0开始。
毕竟刚开始都是打着debugger缺啥补啥,大家先掌握那些基本的语法。
---
所以先知道怎么补之后,再来决定用什么方法获取对象的属性或方法。
```js
document = {
createElement:function(x){
return {}
}
}
var _getXxx = {
toString: function() {
return ""
}
};
_getXxx.__proto__.getA = function getA(x) {
return {}
};
```
比如给document补一些方法
```js
var document = {
createEvent: function createEvent() {},
addEventListener: function addEventListener(x) {},
createElement: function createElement(x) {
if(x===""){} else {}
}
};
```
比如给 getLX_method 对象增加方法。
```js
var getLX_method = {};
getLX_method.__proto__.getExtension = function getExtension(x) {
return {}
}
getLX_method.__proto__.getParameter = function getParameter(x) {
return ""
}
```
比如补 canvas 的话,我们只需要看它调用的方法和返回的结果,然后去一次性绘制图片,取出base64值放到toDataURL()中即可。
```js
document = {
createElement: function createElement(x) {
return canvas
}
};
canvas = {
toDataURL: function toDataURL() {
return "data:image/png;base64,i.....ggg=="
},
getContext: function getContext(x) {
if (x === "xxx") {
return
} else {
return CanvasContext
}
}
};
CanvasContext = {
arc: function arc() {},
stroke: function stroke() {},
fillText: function fillText() {},
toString: function() {
return "[object]"
}
};
canvas[Symbol.toStringTag] = "HTMLCanvasElement";
```
重写String的查找方法
```js
var _indexOf = String.prototype.indexOf;
String.prototype.indexOf = function (searchValue, fromIndex) {
if (searchValue == 'lx') {
return-1;
}
return _indexOf.apply(this, [searchValue, fromIndex]);
}
```
重写toString方法:
```js
var newString = Function.prototype.toString;
Function.prototype.toString = function () {
if (this == Window || this == Location || this == Function.prototype.toString) {
return"function Window() { [native code] }";
}
return newString.apply(this);
};
```
再给大家分享一些补环境经验:
1、检测环境记心里,指纹信息重获取。
2、dom操作记一记,Jsdom多练习。
3、不可变对象记得Object.freeze()
4、多用debugger巧用proxy
5、内置方法防重写
6、形成框架方便二次修改
================================================
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t0 浏览器指纹解读.md
================================================
科普文,简单解读浏览器指纹相关内容,如有描述不周望谅解。
---
## 浏览器指纹
浏览器指纹很重要,在数据采集、搜索引擎、埋点分析、网站测试等方面都有体现。
指纹通常是指服务端的为了做识别而收集的客户端设备信息。即使没有cookie,指纹也可用于识别个人用户或设备。
比如常用于记录的指纹 Header、Cookie、IP、DNS、UserAgent,Font(字体列表),Language,localStorage、Plugin(插件),Canvas(渲染绘图),WebGL(3D渲染图形),Web Vendor,Timezone(时区),WebRTC,ScreenResolution(分辨率),Platform(系统),Audio(音频设置和硬件特征指纹),以及enumerateDevices(其他媒体设备)、CPU、GPU信息等等。

像用户代理、HTML元素属性、Dom对象操作等都属于基本指纹。
像图形渲染、音频指纹、硬件指纹这些属于高级指纹,生成或者模拟都有一定难度。
像浏览记录、访问频率等属于行为指纹,常用于恶意访问的判定,具体判定规则需要测试。
当你浏览页面时,网站可以根据你的浏览器指纹进行跟踪,此外还有一些网站会根据指纹信息生成设备ID然后发送行为日志。
所以在你访问了一个网站后,它虽然没有cookie,但是有一个唯一的指纹,所以无论是推送广告还是行为检测都非常容易。
在线查看浏览器指纹:
- https://www.deviceinfo.me/ (非常详细的设备信息)
- https://www.yalala.com/ (单一特征的指纹)
- http://uniquemachine.org/ (特征合一的指纹)
- https://pixelscan.net/ (像素扫描信息)
- https://ja3er.com/ (ja3 SSL指纹)
- https://iphey.com/#loc-text (以IP为主的数字身份)
- http://dnscookie.com/ (NDS cookie指纹)
- https://amiunique.org/fp
- https://firstpartysimulator.net/kcarter?
---
## chromedriver指纹
不论是selenium或者puppeteer或者playwright,基于chromedriver封装的自动化工具库都很容易被网站监测,所以如何应对指纹检测对使用者来说非常重要。
比如特征参数 webdriver,启动参数no-first-run、window-size、log-level、start-maximized、no-sandbox等,用户特征 user_data_dir、language,以及一些html类型Webelement等。
设置 webdriver为flase:
```python
broser.execute_cdp_cmd(
"Page.addScriptToEvaluateOnNewDocument",
{
"source": """
Object.defineProperty(window, 'navigator', {
value: new Proxy(navigator, {
has: (target, key) => (key === 'webdriver' ? false : key in target),
get: (target, key) =>
key === 'webdriver' ?
false :
typeof target[key] === 'function' ?
target[key].bind(target) :
target[key]
})
});
"""
},
)
```
具体方法可以参考 undetected-chromedriver 开源库,源码中给出了丰富的解决方法。
---
## 隐藏指纹的插件
Canvas Fingerprint Defender 隐藏canvas,不适用于最新chrome
AudioContext Fingerprint Defender-AudioContext 伪造指纹
Chameleon by sereneblue 修改UA、分辨率、语言等
一些插件已经不适用于新版google的 manifest_version 要求, 那我们也可以手动去禁用一些指纹,比如Canvas 、WebGL,或者直接禁用JavaScript,但是会影响网站正常运行。
甚至于禁用JavaScript后,一些网站还会根据页面的CSS样式表来获取信息。
---
## 修改指纹的浏览器
所以有时候可以使用指纹浏览器来进行调试。
巨象浏览器
AdsPower浏览器
阿拉鱼指纹浏览器
hubstudio指纹浏览器
洋葱浏览器
---
## 反爬指纹的生成
目前常见的反爬指纹有
- 基于某种算法的请求指纹(如:TLS-Ja3、报文指纹)
- 基于某种算法生成的环境指纹 (如:fingerprint2)
- 基于服务器预设文件执行结果返回的接口调用信息(如:日志)
- 基于浏览器对服务器不同参数的动画渲染提取出浏览器的帧数信息
这些指纹都可生成一个动态值在接口中校验,无论是在验证请求或者是数据解密。
不过指纹用于检验时都是结合起来使用的,比如把fingerprint和结合起来形成新的指纹ID。

比如https://fingerprintjs.com/demo/的示例。
其算法与浏览器信息生成和设备关联的唯一标识符,用于访问识别,具体方法可阅读官方文档。

---
## canvas指纹
在线查看:[https://browserleaks.com/canvas](https://browserleaks.com/canvas)
Canvas 是一种 HTML5 API,相当于一个画布,用于通过 JavaScript 脚本在网页上绘制图形和动画。
因为Canvas 在不同操作系统不同浏览器上所产生的图片内容基本不同,所以其可用作浏览器指纹识别中的特征,用于标识身份。
但是需要注意 canvas 指纹并不具备唯一性,所以常和其他指纹结合起来计算唯一身份ID。


那在Js中如何获取Canvas 指纹呢,通常是基于Canvas 绘制特定内容的图片,然后使用 canvas.toDataURL()方法返回该图片内容的base64编码字符串,这一点在我们补环境时也经常遇到。
---
## 音频指纹
浏览器音频指纹AudioContext 测试地址 :https://audiofingerprint.openwpm.com/
AudioContext接口表示由链接在一起的音频模块构建的音频处理图,音频上下文控制它包含的节点的创建和音频处理或解码的执行。
在FingerprintJS2有获取音频指纹的代码。

---
## 简述补浏览器环境
所谓的补环境是指在Node环境中去运行浏览器的代码,因为Node环境和浏览器环境是不同的,比如DOM渲染和浏览器内置方法,而经常需要补的内容也是这些。
笔者总结的补环境有两种方式,一是在本地Node中扣代码补环境,二是通过驱动开启一个浏览器环境去执行代码,但是需要记得补驱动的特征。
不过最优的方法还是在本地补,所以这里简单分享一些补的方法和代码。
比如给document补一些方法
```js
var document = {
createEvent: function createEvent() {},
addEventListener: function addEventListener(x) {},
createElement: function createElement(x) {
if(x===""){} else {}
}
};
```
比如给 getLX_method 对象增加方法。
```js
var getLX_method = {};
getLX_method.__proto__.getExtension = function getExtension(x) {
return {}
}
getLX_method.__proto__.getParameter = function getParameter(x) {
return ""
}
```
比如补 canvas 的话,我们只需要看它调用的方法和返回的结果,然后去一次性绘制图片,取出base64值放到toDataURL()中即可。
```js
document = {
createElement: function createElement(x) {
return canvas
}
};
canvas = {
toDataURL: function toDataURL() {
return "data:image/png;base64,i.....ggg=="
},
getContext: function getContext(x) {
if (x === "xxx") {
return
} else {
return CanvasContext
}
}
};
CanvasContext = {
arc: function arc() {},
stroke: function stroke() {},
fillText: function fillText() {},
toString: function() {
return "[object]"
}
};
canvas[Symbol.toStringTag] = "HTMLCanvasElement";
```
重写String的查找方法
```js
var _indexOf = String.prototype.indexOf;
String.prototype.indexOf = function (searchValue, fromIndex) {
if (searchValue == 'lx') {
return-1;
}
return _indexOf.apply(this, [searchValue, fromIndex]);
}
```
重写toString方法:
```js
var newString = Function.prototype.toString;
Function.prototype.toString = function () {
if (this == Window || this == Location || this == Function.prototype.toString) {
return"function Window() { [native code] }";
}
return newString.apply(this);
};
```
再给大家分享一些补环境经验:
1、检测环境记心里,指纹信息重获取。
2、dom操作记一记,Jsdom多练习。
3、不可变对象记得Object.freeze()
4、多用debugger巧用proxy
5、内置方法防重写
6、形成框架方便二次修改
================================================
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t1.js
================================================
// 最基础的
var glb;
var window = global;
window.document = {referrer: ""};
window.location = {
hash: "",
host: "",
hostname: "",
href: "",
origin: "",
pathname: "/",
port: "",
protocol: "https:",
search: ""
};
window.navigator = {
appCodeName: "Mozilla",
appName: "Netscape",
appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36",
cookieEnabled: true,
deviceMemory: 8,
doNotTrack: null,
hardwareConcurrency: 4,
language: "zh-CN",
languages: ["zh-CN", "zh"],
maxTouchPoints: 0,
onLine: true,
platform: "Win32",
product: "Gecko",
productSub: "20030107",
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36",
vendor: "Google Inc.",
vendorSub: "",
};
function get_signature(url) {
_signature = "";
return _signature;
}
// Js代码位置
url = '';
console.log(get_signature(url));
================================================
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t2.js
================================================
// jsdom
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const dom = new JSDOM(`Hello Lx
`);
window = global;
var document = dom.window.document;
var params = {
location:{
hash: "",
host: "",
hostname: "",
href: "",
protocol: "",
search: "",
},
navigator:{
appCodeName: "Mozilla",
appName: "Netscape",
appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36",
cookieEnabled: true,
deviceMemory: 8,
hardwareConcurrency: 4,
language: "zh-CN",
onLine: true,
platform: "MacIntel",
product: "Gecko",
productSub: "20030107",
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Safari/537.36",
vendor: "Google Inc."
},
screen:{
availHeight: 728,
availLeft: 0,
availTop: 0,
availWidth: 1366,
colorDepth: 24,
height: 768,
pixelDepth: 24,
width: 1366
}
};
Object.assign(window,params);
window.document = document;
// Js代码位置
function get_signature(url) {
_signature = "";
return _signature
}
console.log(get_signature(url));
================================================
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t3.js
================================================
var exports = undefined
, module = undefined
, Image = function Image() {}
, PluginArray = function PluginArray() {}
, indexedDB = {}
, DOMException = function DOMException() {}
, WebSocket = function WebSocket() {}
, Request = function Request() {}
, Headers = function Headers() {};
var localStorage = {
getItem: function getItem(x) {return null},
removeItem: function removeItem(x) {}
};
var sessionStorage = {
getItem: function getItem(x) {return null},
removeItem: function removeItem(x) {}
};
var MimeType = {
description: "Native Client Executable",
suffixes: "",
type: "application/x-nacl"
};
MimeType[Symbol.toStringTag] = "MimeType";
var navigator = {
plugins: {
0: {
0: MimeType,
name: "Native Client",
length: 2,
filename: "internal-nacl-plugin",
description: "",
length: 1
}
},
webdriver: false,
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36",
languages: ["zh-CN", "zh"],
appCodeName: "Mozilla",
appName: "Netscape",
appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36",
platform: "Win32"
};
navigator.plugins[0]["application/x-nacl"] = MimeType;
navigator.plugins[0].__proto__.item = function item() {
return MimeType
};
navigator.plugins[Symbol.toStringTag] = "PluginArray";
navigator.plugins[0][Symbol.toStringTag] = "Plugin";
navigator.plugins[0][0].enabledPlugin = navigator.plugins[2];
var CanvasRenderingContext2D_ = {
toString: function() {
return "[object CanvasRenderingContext2D]"
}
};
CanvasRenderingContext2D_.__proto__.fillText = function fillText() {}
;
CanvasRenderingContext2D_.__proto__.arc = function arc() {}
;
CanvasRenderingContext2D_.__proto__.stroke = function stroke() {}
;
var getContext_ = {
toString: function() {
return "[object WebGLRenderingContext]"
}
};
var aaaaa=0;
var canvas = {
toDataURL: function toDataURL() {
if(aaaaa=0){
aaaaa=aaaaa+1
return "[native code]"
}
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"
},
getContext: function getContext(x) {
if (x === "2d") {
return CanvasRenderingContext2D_
} else {
return getContext_
}
}
};
canvas[Symbol.toStringTag] = "HTMLCanvasElement";
canvas.getContext[Symbol.toStringTag] = "WebGLRenderingContext";
getContext_.__proto__.getExtension = function getExtension(x) {
return {
UNMASKED_RENDERER_WEBGL: 37446,
UNMASKED_VENDOR_WEBGL: 37445
}
}
;
getContext_.__proto__.getParameter = function getParameter(x) {
return "Google Inc. (Intel)/ANGLE (Intel, Intel(R) UHD Graphics Direct3D11 vs_5_0 ps_5_0, D3D11-27.20.100.8681)"
}
;
var location = {
href: "https://www.douyin.com/",
toString: function() {
return location.href
},
protocol: "https:"
};
var document = {
createEvent: function createEvent() {},
location: location,
cookie: "",
vlinkColor: "",
referrer: "",
fgColor: "",
dir: "",
addEventListener: function addEventListener(x) {},
createElement: function createElement(x) {
return canvas
}
};
document.createElement[Symbol.toStringTag] = "HTMLImageElement";
var history = {
length: 1,
scrollRestoration: "auto",
state: null
};
var upload = {
onabort: null,
onerror: null,
onload: null,
onloadend: null,
onloadstart: null,
onprogress: null,
ontimeout: null
};
upload[Symbol.toStringTag] = "XMLHttpRequestUpload";
var XMLHttpRequest = function() {
this.onabort = null,
this.onerror = null,
this.onload = null,
this.onloadend = null,
this.onloadstart = null,
this.onprogress = null,
this.onreadystatechange = null,
this.ontimeout = null,
this.readyState = 0,
this.response = "",
this.responseText = "",
this.responseType = "",
this.responseURL = "",
this.responseXML = null,
this.status = 0,
this.statusText = "",
this.timeout = 0,
this.upload = upload,
this.withCredentials = false
};
XMLHttpRequest.prototype.open = function() {
function ee() {
this.openArgs = arguments
}
function Vn(e, t) {
var n = "function" == typeof Symbol && e[Symbol.iterator];
if (!n)
return e;
var r, o, i = n.call(e), a = [];
try {
for (; (void 0 === t || t-- > 0) && !(r = i.next()).done; )
a.push(r.value)
} catch (e) {
o = {
error: e
}
} finally {
try {
r && !r.done && (n = i.return) && n.call(i)
} finally {
if (o)
throw o.error
}
}
return a
}
;function a() {
for (var t = [], n = 0; n < arguments.length; n++)
t[n] = arguments[n];
var r = Vn(t, 2)
, o = r[0]
, i = r[1];
return this._url = i || "",
this._method = o && o.toLowerCase() || "",
ee.apply(this, t)
}
;for (var e = [], t = 0; t < arguments.length; t++)
e[t] = arguments[t];
return a.apply(this, e)
}
;
XMLHttpRequest.prototype.setRequestHeader = function() {
function a() {
for (var t = [], n = 0; n < arguments.length; n++)
t[n] = arguments[n];
return this._requestHeaders = this._requestHeaders || [],
this._requestHeaders.push(t)
}
;for (var e = [], t = 0; t < arguments.length; t++)
e[t] = arguments[t];
return a.apply(this, e)
}
;
XMLHttpRequest.prototype.send = function() {
function Wn(e, t) {
for (var n = 0, r = t.length, o = e.length; n < r; n++,
o++)
e[o] = t[n];
return e
}
;function Vn(e, t) {
var n = "function" == typeof Symbol && e[Symbol.iterator];
if (!n)
return e;
var r, o, i = n.call(e), a = [];
try {
for (; (void 0 === t || t-- > 0) && !(r = i.next()).done; )
a.push(r.value)
} catch (e) {
o = {
error: e
}
} finally {
try {
r && !r.done && (n = i.return) && n.call(i)
} finally {
if (o)
throw o.error
}
}
return a
}
;qr = function(e, t, n) {
return function() {
for (var r = [], o = 0; o < arguments.length; o++)
r[o] = arguments[o];
if (!e)
return hr;
var i = e[t]
, a = n.apply(void 0, Wn([i], Vn(r)))
, s = a;
return Yn(s) && (s = function() {
for (var e = [], t = 0; t < arguments.length; t++)
e[t] = arguments[t];
try {
return a.apply(this, e)
} catch (t) {
return Yn(i) && i.apply(this, e)
}
}
),
e[t] = s,
function(n) {
n && s !== e[t] || (e[t] = i)
}
}
}
;
function Yn(e) {
return "function" == typeof e
}
;Jr = function(e) {
return qr(e, "onreadystatechange", (function(t, n, r, o, i) {
return function() {
for (var a = [], s = 0; s < arguments.length; s++)
a[s] = arguments[s];
return 4 === this.readyState && o && o({
name: Gr,
type: "get",
event: Wr(e, n, r, i)
}),
t && t.apply(this, a)
}
}
))
}
;
n = function(t) {
r.chechIsReady() ? e.prototype.sendEvent.call(r, t) : r.preQueue.push(t)
}
;
function ew() {
var t = this
, n = this.openArgs
, r = arguments
, o = n[0] || "GET"
, i = new URL(n[1],window.location.href);
}
;function a() {
for (var i = [], a = 0; a < arguments.length; a++)
i[a] = arguments[a];
return Jr(this)({}, null, n, "https://www.douyin.com/"),
this._start = Date.now(),
this._data = null == i ? void 0 : i[0],
ew.apply(this, i)
}
;for (var e = [], t = 0; t < arguments.length; t++)
e[t] = arguments[t];
return a.apply(this, e)
}
;
XMLHttpRequest.prototype.overrideMimeType = function overrideMimeType() {}
;
XMLHttpRequest.prototype[Symbol.toStringTag] = "XMLHttpRequest";
var window = {
queueMicrotask: queueMicrotask,
setTimeout: setTimeout,
setInterval: setInterval,
clearTimeout: clearTimeout,
clearInterval: clearInterval,
TextEncoder: TextEncoder,
URLSearchParams: URLSearchParams,
URL: URL,
WebAssembly: WebAssembly,
//WeakRef: WeakRef,
//FinalizationRegistry: FinalizationRegistry,
Atomics: Atomics,
SharedArrayBuffer: SharedArrayBuffer,
isNaN: isNaN,
isFinite: isFinite,
eval: eval,
unescape: unescape,
escape: escape,
encodeURIComponent: encodeURIComponent,
encodeURI: encodeURI,
decodeURIComponent: decodeURIComponent,
decodeURI: decodeURI,
Reflect: Reflect,
Proxy: Proxy,
WeakSet: WeakSet,
WeakMap: WeakMap,
Set: Set,
BigInt: BigInt,
Map: Map,
DataView: DataView,
BigInt64Array: BigInt64Array,
BigUint64Array: BigUint64Array,
Uint8ClampedArray: Uint8ClampedArray,
Float64Array: Float64Array,
Float32Array: Float32Array,
Int32Array: Int32Array,
Uint32Array: Uint32Array,
Int16Array: Int16Array,
Uint16Array: Uint16Array,
Int8Array: Int8Array,
Uint8Array: Uint8Array,
ArrayBuffer: ArrayBuffer,
Intl: Intl,
Math: Math,
JSON: JSON,
URIError: URIError,
TypeError: TypeError,
SyntaxError: SyntaxError,
ReferenceError: ReferenceError,
RangeError: RangeError,
EvalError: EvalError,
Error: Error,
Promise: Promise,
Date: Date,
Symbol: Symbol,
String: String,
Boolean: Boolean,
undefined: undefined,
NaN: NaN,
Infinity: Infinity,
parseInt: parseInt,
parseFloat: parseFloat,
Number: Number,
Array: Array,
Function: Function,
Object: Object,
navigator: navigator,
location: location,
document: document,
history: history,
indexedDB: indexedDB,
localStorage: localStorage,
sessionStorage: sessionStorage,
RegExp: RegExp,
XMLHttpRequest: XMLHttpRequest,
fetch: function fetch() {return "[native code]"},
console: console,
HTMLElement: function HTMLElement() {},
chrome: {
"app": {
"isInstalled": false,
"InstallState": {
"DISABLED": "disabled",
"INSTALLED": "installed",
"NOT_INSTALLED": "not_installed"
},
"RunningState": {
"CANNOT_RUN": "cannot_run",
"READY_TO_RUN": "ready_to_run",
"RUNNING": "running"
}
},
"runtime": {
connect: function connect() {return "[native code]"},
"OnInstalledReason": {
"CHROME_UPDATE": "chrome_update",
"INSTALL": "install",
"SHARED_MODULE_UPDATE": "shared_module_update",
"UPDATE": "update"
},
"OnRestartRequiredReason": {
"APP_UPDATE": "app_update",
"OS_UPDATE": "os_update",
"PERIODIC": "periodic"
},
"PlatformArch": {
"ARM": "arm",
"ARM64": "arm64",
"MIPS": "mips",
"MIPS64": "mips64",
"X86_32": "x86-32",
"X86_64": "x86-64"
},
"PlatformNaclArch": {
"ARM": "arm",
"MIPS": "mips",
"MIPS64": "mips64",
"X86_32": "x86-32",
"X86_64": "x86-64"
},
"PlatformOs": {
"ANDROID": "android",
"CROS": "cros",
"LINUX": "linux",
"MAC": "mac",
"OPENBSD": "openbsd",
"WIN": "win"
},
"RequestUpdateCheckStatus": {
"NO_UPDATE": "no_update",
"THROTTLED": "throttled",
"UPDATE_AVAILABLE": "update_available"
}
}
}
};
window[Symbol.toStringTag] = "Window";
navigator[Symbol.toStringTag] = "Navigator";
location[Symbol.toStringTag] = "Location";
document[Symbol.toStringTag] = "HTMLDocument";
history[Symbol.toStringTag] = "History";
indexedDB[Symbol.toStringTag] = "IDBFactory";
localStorage[Symbol.toStringTag] = "Storage";
sessionStorage[Symbol.toStringTag] = "Storage";
Object.prototype.constructor.getOwnPropertyNames = function(x) {
if (toString.call(x) == "[object Navigator]") {
return []
} else {
return Object.keys(x)
}
}
function mu_() {
var e = [];
var a = "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (var b = 0; b < 28; b++) {
e[b] = a[Math.floor(Math.random() * a.length)]
}
;return e.join('')
}
Object.freeze(navigator);
Object.freeze(document);
Object.freeze(location);
Object.freeze(history);
Object.freeze(indexedDB);
Object.freeze(localStorage);
Object.freeze(sessionStorage);
================================================
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t4.js
================================================
// 从浏览器直接扒各种参数环境的脚本,忘记当时转谁的了,请联系我增加署名
console.log(make_all()) // 使用时候解开该行注释,然后将生成的代码都放到控制台中直接执行,复制生成的字符出即可。
function get_all(){
function generatecode4v(name_, key, v, o, be_values) {
if (be_values.indexOf(key) == -1){
if (typeof (v) == "object") {
if (v == null) {
return `${name_}["${key}"] = null;\r\n`
}
if (o == v){
return `${name_}["${key}"] = ${name_};\r\n`
}
try {
return `${name_}["${key}"] = _vPxy(new class ${v.constructor.name}{}, "${key}");\r\n`
} catch (error) {
return `${name_}["${key}"] = "----------------------------------------------------------------";\r\n`
}
}
if (typeof (v) == "string") {
if (v.indexOf('"') == -1){
return `${name_}["${key}"] = "${v}";\r\n`
}else if (v.indexOf("'") == -1){
return `${name_}["${key}"] = '${v}';\r\n`
}else{
return `${name_}["${key}"] = \`${v}\`;\r\n`
}
}
if (typeof (v) == "function") {
return `${name_}["${key}"] = function ${v.name}(){_vLog('--- func(*) --- ${v.name}');debugger;}; safefunction(${name_}["${key}"]);\r\n`
}
}else{
return `${name_}["${key}"] = ${JSON.stringify(v)};\r\n`
}
return `${name_}["${key}"] = ${v};\r\n`
}
function generatecode4v1(name_, key, v, o, be_values) {
if (be_values.indexOf(key) == -1){
if (typeof (v) == "object") {
if (v == null) {
return `${name_}.__proto__["${key}"] = null;\r\n`
}
try {
return `${name_}.__proto__["${key}"] = _vPxy(new class ${v.constructor.name}{}, "${key}");\r\n`
} catch (error) {
return `${name_}.__proto__["${key}"] = "----------------------------------------------------------------";\r\n`
}
}
if (typeof (v) == "string") {
if (v.indexOf('"') == -1){
return `${name_}.__proto__["${key}"] = "${v}";\r\n`
}else if (v.indexOf("'") == -1){
return `${name_}.__proto__["${key}"] = '${v}';\r\n`
}else{
return `${name_}.__proto__["${key}"] = \`${v}\`;\r\n`
}
}
if (typeof (v) == "function") {
return `${name_}.__proto__["${key}"] = function ${v.name}(){_vLog('--- func(*) --- ${v.name}');debugger;}; safefunction(${name_}["${key}"]);\r\n`
}
if (name_ == 'document' && key == 'all'){
return `${name_}.__proto__["${key}"] = undefined;\r\n`
}
if (name_ == 'document' && key == 'body'){
return `${name_}.__proto__["${key}"] = _vPxy(new class HTMLBodyElement{}, "body");\r\n`
}
}else{
return `${name_}.__proto__["${key}"] = ${JSON.stringify(v)};\r\n`
}
return `${name_}.__proto__["${key}"] = ${v};\r\n`
}
function generate4example(example, name_, skips, be_values) {
var code = "";
var protos = {}
if (typeof (example) == "object" && example.prototype == undefined) {
for (let key in example.__proto__) {
protos[key] = true;
}
for (let key in example) {
if (protos[key] == undefined) {
if (key && skips.indexOf(key) == -1){
try{
code += generatecode4v(name_, key, example[key], example, be_values);
}catch(e){
console.log('========== error ==========')
console.log(key)
console.log(e)
}
}
}
}
}
return alignment_safefunction(alignment(code));
}
function generate4Prototype(example, name_, skips, be_values) {
var code = "";
if (typeof (example) == "object" && example.prototype == undefined) {
for (let key in example.__proto__) {
if (skips.indexOf(key) == -1){
try{
code += generatecode4v1(name_, key, example[key], example, be_values);
}catch(e){
console.log('========== error ==========')
console.log(key)
console.log(e)
}
}
}
}
return alignment_safefunction(alignment(code))
}
function alignment(str){
var max_protolen = 0
if (str.trim().length == 0){
return str
}
var mch = str.match(/(\["[^"]+"\]) *=/g)
if (!(mch)){
return str
}
mch.map(function(e){
if (e.length > max_protolen){
max_protolen = e.length
}
})
return str.replace(/(\["[^"]+"\]) *=/g, function(_, e){
return e + Array(max_protolen-e.length-1).fill(" ").join("") + '='
})
}
function alignment_safefunction(str){
var max_protolen = 0
if (str.trim().length == 0){
return str
}
var mch = str.match(/(=[^=]+); *safefunction/g)
if (!(mch)){
return str
}
mch.map(function(e){
if (e.length > max_protolen){
max_protolen = e.length
}
})
return str.replace(/(=[^=]+;) *safefunction/g, function(_, e){
return e + Array(max_protolen-e.length-14).fill(" ").join("") + 'safefunction'
})
}
function vall(example, name_, skips, be_values){
skips = skips || []
be_values = be_values || []
var protostr = generate4Prototype(example, name_, skips, be_values)
var objectstr = generate4example(example, name_, skips, be_values)
return protostr + objectstr
}
vall.generate4example = generate4example
vall.generate4Prototype = generate4Prototype
// placeholder1
}
function make_all(){
var ret;
ret = Cilame + '\r\n'
ret += get_all + '\r\n'
ret = ret.replace('// placeholder1', `
console.log(
Cilame + "\\r\\n" +
"Cilame()\\r\\n" +
vall(window, "window", ${JSON.stringify(Cilame())}.concat(['_vLog', '_vPxy','setTimeout', 'setInterval', 'clearInterval', 'clearTimeout'])) +
vall(document, "document", ['cookie', 'addEventListener', 'dispatchEvent', 'removeEventListener', "createElement", "getElementsByName"]) +
vall(Node.prototype, "Node.prototype", ["location", 'addEventListener', 'dispatchEvent', 'removeEventListener']) +
vall(navigator, "navigator", ['connection', 'getBattery', 'mimeTypes'], ['languages']) +
vall(window.location, "window.location") +
vall(window.localStorage, "window.localStorage", ["clear", "getItem", "key", "removeItem", "setItem", "length"]) +
vall(window.sessionStorage, "window.sessionStorage", ["clear", "getItem", "key", "removeItem", "setItem", "length"]) +
\`for (let key in navigator.__proto__) {
navigator[key] = navigator.__proto__[key];
if (typeof (navigator.__proto__[key]) != "function") {
navigator.__proto__.__defineGetter__(key, function() {
debugger ;var e = new Error();
e.name = "TypeError";
e.message = "Illegal invocation";
e.stack = "VM988:1 Uncaught TypeError: Illegal invocation \\\\r\\\\n at :1:19";
throw e;
});
}
}
window = VmProxyB(window, "window", true) // 这三个暂时不打印获取的结果
window.document = VmProxyB(window.document, "window.document", true) // 这三个暂时不打印获取的结果
window.navigator = VmProxyB(window.navigator, "window.navigator", true) // 这三个暂时不打印获取的结果
window.location = VmProxyB(window.location, "window.location")
window.localStorage = VmProxyB(window.localStorage, "window.localStorage")
window.sessionStorage = VmProxyB(window.sessionStorage, "window.sessionStorage")
window.XMLHttpRequest = VmProxyB(window.XMLHttpRequest, "window.XMLHttpRequest")
window.indexedDB = VmProxyB(window.indexedDB, "window.indexedDB")
// 该处用于一些定制的挂钩处理,绕过 Function 或 eval 函数内一些检测使用的,视情况修改
function temp_hookFunc(H){
eval(\\\`
_v\\\${H.split('.').pop()} = \\\${H}
window.\\\${H} = function \\\${H.split('.').pop()}(){
if (start){
console.log('-------------------- \\\${H}(*) --------------------')
console.log(arguments[0])
}
if (arguments[0].indexOf('__dirname') != -1 || arguments[0].indexOf('__filename') != -1){
return function (){}
}
return _v\\\${H.split('.').pop()}.apply(this, arguments)
}
safefunction(window.\\\${H})
\\\`)
}
temp_hookFunc('Function')
// hookFunc('Function')
// 目前就使用这样的方式将 setTimeout/setInterval 钩住使用,这两个函数都有点特殊,需要特别关注
window.setTimeout = safefunction(function setTimeout(func, time){
if ((time||0) < 100){ console.log(' [setTimeout] immediately.', func); func() }
else{ console.log(' [setTimeout] not run. cos interval over 100:', time) }
})
window.setInterval = safefunction(function setInterval(func, time){
if ((time||0) < 100){ console.log(' [setInterval] immediately (only run once).', func); func() }
else{ console.log(' [setInterval] not run. cos interval over 100:', time) }
})
hookFunc("clearInterval")
hookFunc("clearTimeout")
hookFunc("Number")
hookFunc("parseFloat")
hookFunc("parseInt")
hookFunc("Symbol")
hookFunc("Error")
hookFunc("ArrayBuffer")
hookFunc("Uint8Array")
hookFunc("Int8Array")
hookFunc("Uint16Array")
hookFunc("Int16Array")
hookFunc("Uint32Array")
hookFunc("Int32Array")
hookFunc("Float32Array")
hookFunc("Float64Array")
hookFunc("Uint8ClampedArray")
hookFunc("BigUint64Array")
hookFunc("BigInt64Array")
hookFunc("decodeURI")
hookFunc("decodeURIComponent")
hookFunc("encodeURI")
hookFunc("encodeURIComponent")
hookFunc("escape")
hookFunc("unescape")
hookFunc("eval")
hookFunc("isFinite")
hookFunc("isNaN")
hookFunc("SharedArrayBuffer")
// 一般这种可以处理 new RegExp(*) 系列的挂钩。
// 如果是直接 /*/ 挂钩不上,不过这种是可以从代码里面明白的找到,这种无法混淆
// 正则的挂钩比较特殊,需要在实例化的时候挂钩上实例对象的函数,所以挂钩处理如下
;(function (){
var _vRegExp = RegExp
window.RegExp = function RegExp(){
var ostart = start
if (ostart){
console.log('-------------------- RegExp(*) --------------------')
console.log(arguments[0])
}
start = false
fakeRegExpObj = _vRegExp.apply(this, arguments)
_fakeRegExp_test = fakeRegExpObj.test
fakeRegExpObj.test = safefunction(function test() {
if (start){
console.log('-------------------- RegExp.prototype.test(*) --------------------')
console.log(this+'', '==>', arguments[0])
}
return _fakeRegExp_test.apply(this, arguments)
})
_fakeRegExp_exec = fakeRegExpObj.exec
fakeRegExpObj.exec = safefunction(function exec() {
if (start){
console.log('-------------------- RegExp.prototype.exec(*) --------------------')
console.log(this+'', '==>', arguments[0])
}
return _fakeRegExp_exec.apply(this, arguments)
})
start = ostart
return fakeRegExpObj
}
safefunction(window.RegExp)
})()
// 挂钩 Object 的各种函数
hookFuncObject("Object.assign")
hookFuncObject("Object.getOwnPropertyDescriptor")
hookFuncObject("Object.getOwnPropertyDescriptors")
hookFuncObject("Object.getOwnPropertyNames")
hookFuncObject("Object.getOwnPropertySymbols")
hookFuncObject("Object.is")
hookFuncObject("Object.preventExtensions")
hookFuncObject("Object.seal")
hookFuncObject("Object.create")
hookFuncObject("Object.defineProperties")
hookFuncObject("Object.defineProperty")
hookFuncObject("Object.freeze")
hookFuncObject("Object.getPrototypeOf")
hookFuncObject("Object.setPrototypeOf")
hookFuncObject("Object.isExtensible")
hookFuncObject("Object.isFrozen")
hookFuncObject("Object.isSealed")
hookFuncObject("Object.keys")
hookFuncObject("Object.entries")
hookFuncObject("Object.values")
// 为了保证函数内部的随机函数在一定程度上固定,这里将 random hook 成一个伪随机函数,保证某些函数计算的稳定。
Math.random = (function(seed) {
return (function random() {
seed = (seed * 9301 + 49297) % 233280, rnd = seed / 233280.0
console.log(' [fake Math.random]', rnd)
return rnd
})
})(0)
hookFunc("Date.parse")
hookFuncReturn("Date.prototype.valueOf")
hookFuncReturn("Date.prototype.getTime")
start = true // 主要的 VmProxyB 的log开关
start1 = true // 一些未被实现的 _vPxy(new class Unknown{}) 的 Proxy 打印日志,让输出更清晰
// 这里插入浏览器给你的代码
// $placeholder_code
runloads()
// 这里往后插入你自己的代码,用于导出/编辑自己使用的函数
\`)`)
ret += '\r\n'
ret += 'get_all()\r\n// 将生成的代码全部拷贝到 chrome 控制台执行即可'
return ret
}
// 以下就是就是一个补环境的简单处理,现在还不成熟,后面慢慢补
function Cilame(){
// 生成一些重要的参数,比如 screen Screen 这种对应的系统对象
// 这些系统对象原型结构稍微有点绕,统一成下面模式就行
;(function(){
const $toString = Function.toString;
const myFunction_toString_symbol = Symbol('('.concat('', ')_', (Math.random() + '').toString(36)));
const myToString = function() {
return typeof this == 'function' && this[myFunction_toString_symbol] || $toString.call(this);
};
function set_native(func, key, value) {
Object.defineProperty(func, key, {
"enumerable": false,
"configurable": true,
"writable": true,
"value": value
})
};
delete Function.prototype['toString'];
set_native(Function.prototype, "toString", myToString);
set_native(Function.prototype.toString, myFunction_toString_symbol, "function toString() { [native code] }");
;(typeof global=='undefined'?window:global).safefunction = function(func){
set_native(func, myFunction_toString_symbol, `function ${myFunction_toString_symbol,func.name || ''}() { [native code] }`);
return func
};(typeof global=='undefined'?window:global).safefunction_with_name = function(func,name){
set_native(func, myFunction_toString_symbol, `function ${myFunction_toString_symbol,name || ''}() { [native code] }`);
return func
};
function make_constructor(name, Name, name_inject_objs, Name_inject_objs, proto, config){
config = config !== undefined?config:{}
var allow_illegal = config['allow_illegal']
var illegalstr = (!allow_illegal)?'throw new TypeError("Illegal constructor");':''
var evalstr = `
var ${name}Constructor = function ${Name=="WindowProperties"?"EventTarget":Name}() { ${illegalstr} }
safefunction(${name}Constructor);
var ${name}Prototype = (proto!==undefined?proto:{});
Object.defineProperties(${name}Prototype, {
constructor: { value: ${name}Constructor, writable: true, configurable: true },
[Symbol.toStringTag]: { value: "${Name}", configurable: true }
});
${name}Constructor.prototype = ${name}Prototype;
var ${Name} = function ${Name}() {}
safefunction(${Name});
var ${name} = new ${Name}();
${name}.__proto__ = ${name}Prototype;
__cilame__['n']["${name}"] = ${name}
__cilame__['N']["${Name}"] = ${Name}
if (name_inject_objs.length){ name_inject_objs.map(function(e){ Object.defineProperty(e, "${name}", { configurable: true, writable: true, value: ${name} }); }) }
if (Name_inject_objs.length){ Name_inject_objs.map(function(e){ Object.defineProperty(e, "${Name}", { configurable: true, writable: true, value: ${name}Constructor }); }) }
`
eval(evalstr)
}
;(typeof global=='undefined'?window:global).make_constructor = make_constructor
;(typeof global=='undefined'?window:global).start = false
;(typeof global=='undefined'?window:global).start1 = false
;(typeof global=='undefined'?window:global)._vLog = function _vLog(){ if (start1){
console.log.apply(console.log, [].slice.call(arguments))
}}
;(typeof global=='undefined'?window:global).myparselog = function myparselog(V){
return typeof V=='string'?
V.length > 100?V.slice(0,100) + '... ':V
:
typeof V=='number'?V:
typeof V=='function'?V:
typeof V=='undefined'?undefined:
typeof V=='boolean'?V:
``
}
;(typeof global=='undefined'?window:global)._vPxy = function(G, M){
var _vLog = (typeof global=='undefined'?window:global)._vLog || console.log
function LS(T, M, F){ return ` [UnProxy] ${M}[${T.constructor.name}].(Prxoy)${F} ==>>`} // 未知对象取值处理时的检查操作
return new Proxy(G, {
apply: function(T, A, L){ _vLog(LS(G, M, 'apply') ); return Reflect.apply(T, A, L) },
construct: function(T, L, N){ _vLog(LS(G, M, 'construct') ); return Reflect.construct(T, L, N) },
deleteProperty: function(T, P){ _vLog(LS(G, M, 'deleteProperty'), P); return Reflect.deleteProperty(T, P) },
get: function(T, P, R){ _vLog(LS(G, M, 'get'), P); return Reflect.get(T, P, R) },
// defineProperty: function(T, P, A){ _vLog(LS(G, M, 'defineProperty') ); return Reflect.defineProperty(T, P, A) },
// getOwnPropertyDescriptor: function(T, P){ _vLog(LS(G, M, 'getOwnPropertyDescriptor') ); return Reflect.getOwnPropertyDescriptor(T, P) },
getPrototypeOf: function(T){ _vLog(LS(G, M, 'getPrototypeOf') ); return Reflect.getPrototypeOf(T) },
has: function(T, P){ _vLog(LS(G, M, 'has'), P); return Reflect.has(T, P) },
isExtensible: function(T){ _vLog(LS(G, M, 'isExtensible') ); return Reflect.isExtensible(T) },
ownKeys: function(T){ _vLog(LS(G, M, 'ownKeys') ); return Reflect.ownKeys(T) },
preventExtensions: function(T){ _vLog(LS(G, M, 'preventExtensions') ); return Reflect.preventExtensions(T) },
set: function(T, P, V, R){ _vLog(LS(G, M, 'set'), P, myparselog(V) ); return Reflect.set(T, P, V, R) },
setPrototypeOf: function(T, P){ _vLog(LS(G, M, 'setPrototypeOf'), P); return Reflect.setPrototypeOf(T, P) },
})
}
function logA(tag, G_or_S, objectname, propertyname, value){
console.table([{tag, G_or_S, objectname, propertyname,value}], ["tag","G_or_S","objectname","propertyname","value"]);
}
function logB(tag, GS, objectname, propertyname, value){
var pro = `[VmProxy] ${tag} ${GS} [${objectname}] "${typeof propertyname=='symbol'?'symbol':propertyname}"`
var emp = function (n){ return n>0?Array(n).fill('=').join('').replace(/=/g, ' '):'' };
console.info(pro + emp(70-pro.length), value);
}
function VmProxy(logger, object_, titlename, dont_log_value){
return new Proxy(object_, {
get (target, property) {
if (start){
logger(titlename, "Get >>", target.constructor.name, property, myparselog(target[property]));
}
return target[property];
},
set (target, property, value) {
if (start){
logger(titlename, "Set <<", target.constructor.name, property, myparselog(value));
}
target[property] = value;
}
});
};
var VmProxyA = function (){return VmProxy.apply(this, [logA].concat([].slice.call(arguments)))}
var VmProxyB = function (){return VmProxy.apply(this, [logB].concat([].slice.call(arguments)))}
;(typeof global=='undefined'?window:global).VmProxyA = VmProxyA
;(typeof global=='undefined'?window:global).VmProxyB = VmProxyB
;(typeof global=='undefined'?window:global).hookFunc = function hookFunc(H){
eval(`
_v${H.split('.').pop()} = ${H}
window.${H} = function ${H.split('.').pop()}(){
if (start){
console.log('-------------------- ${H}(*) --------------------')
console.log(myparselog(arguments[0]))
}
return _v${H.split('.').pop()}.apply(this, arguments)
}
safefunction(window.${H})
`)
}
;(typeof global=='undefined'?window:global).hookFuncObject = function hookFuncObject(H){
eval(`
_v${H.split('.').pop()} = ${H}
window.${H} = function ${H.split('.').pop()}(){
if (start){
console.log('-------------------- ${H}(*) --------------------')
console.log(arguments)
}
return _v${H.split('.').pop()}.apply(this, arguments)
}
safefunction(window.${H})
`)
}
;(typeof global=='undefined'?window:global).hookFuncReturn = function hookFuncReturn(H){
eval(`
_v${H.split('.').pop()} = ${H}
window.${H} = function ${H.split('.').pop()}(){
var v = _v${H.split('.').pop()}.apply(this, arguments)
if (start){
console.log('-------------------- ${H}(*) --------------------')
console.log(myparselog(v))
}
return v
}
safefunction(window.${H})
`)
}
})();
// 将核心结构初始化,也就是 window navigator document 等初始化处理好
var __cilame__ = { 'n':{}, 'N':{}, 'c':{} } // 临时存储空间, n 为 new 对象, N 为原始方法.
var GL = _global = (typeof global=='undefined'?window:global)
make_constructor("eventTarget", "EventTarget", [], [GL], undefined, { allow_illegal: true })
EventTarget.prototype.listeners = {};
EventTarget.prototype.addEventListener = safefunction(function addEventListener(type, callback) {
console.log(' [addEventListener]', type, callback)
if(!(type in this.listeners)) { this.listeners[type] = []; }
this.listeners[type].push(callback);
})
EventTarget.prototype.removeEventListener = safefunction(function removeEventListener(type, callback) {
console.log(' [removeEventListener]', type, callback)
if(!(type in this.listeners)) { return; }
var stack = this.listeners[type];
for(var i = 0, l = stack.length; i < l; i++) { if(stack[i] === callback){ stack.splice(i, 1); return this.removeEventListener(type, callback); } }
})
EventTarget.prototype.dispatchEvent = safefunction(function dispatchEvent(event) {
console.log(' [dispatchEvent]', event)
if(!(event.type in this.listeners)) { return; }
var stack = this.listeners[event.type];
event.target = this;
for(var i = 0, l = stack.length; i < l; i++) { stack[i].call(this, event); }
})
make_constructor("windowProperties", "WindowProperties", [], [], new EventTarget, { allow_illegal: true })
make_constructor("window", "Window", [GL], [GL], __cilame__['n']['windowProperties']) // WindowProperties 没有注入 window 环境
window["TEMPORARY"] = 0;
window["PERSISTENT"] = 1;
window = new Proxy(window, {
get: function(a,b,c){ return a[b] || global[b] },
set: function(a,b,c){ return a[b] = global[b] = c }
})
// window 生成之后将 global 内部的常用函数直接传到 window 里面
var Gkeys = Object.getOwnPropertyNames(global), exclude = ['global', 'process', '_global']
for (var i = 0; i < Gkeys.length; i++) {
if (exclude.indexOf(Gkeys[i]) == -1){ window[Gkeys[i]] = global[Gkeys[i]] }
}
var EN = normal_env = [window, GL]
make_constructor("navigator", "Navigator", EN, EN)
window.clientInformation = navigator
// 处理 document 初始化
make_constructor("_vNode", "Node", [], EN, new EventTarget)
make_constructor("_vDocument", "Document", [], EN, __cilame__["n"]['_vNode'], { allow_illegal: true })
make_constructor("document", "HTMLDocument", EN, EN, __cilame__["n"]['_vDocument'])
;(function(){
'use strict';
var cookie_cache = document.cookie = "";
Object.defineProperty(document, 'cookie', {
get: function() {
console.log('==>> Get Cookie', cookie_cache);
return cookie_cache;
},
set: function(val) {
console.log('<<== Set Cookie', val);
var cookie = val.split(";")[0];
var ncookie = cookie.split("=");
var flag = false;
var cache = cookie_cache.split("; ");
cache = cache.map(function(a) {
if (a.split("=")[0] === ncookie[0]) {
flag = true;
return cookie;
}
return a;
})
cookie_cache = cache.join("; ");
if (!flag) {
cookie_cache += cookie + "; ";
}
return cookie_cache;
}
});
global.init_cookie = function init_cookie(str){
cookie_cache = str
}
})();
// 处理 location 初始化,以及绑定 document
make_constructor("location", "Location", EN, EN)
location["ancestorOrigins"] = _vPxy(new (class DOMStringList {}), "location.ancestorOrigins");
location["assign"] = function assign(U){ console.log(" [location] assign", U);}; safefunction(location["assign"]);
location["reload"] = function reload(){ console.log(" [location] reload");}; safefunction(location["reload"]);
location["replace"] = function replace(U){ console.log(" [location] replace", U);}; safefunction(location["replace"]);
Object.defineProperty(location, 'href', {
get: function(){
return location.protocol + "//" + location.host + (location.port ? ":" + location.port : "") + location.pathname + location.search + location.hash;
},
set: function(href){
var a = href.match(/([^:]+:)\/\/([^/:?#]+):?(\d+)?([^?#]*)?(\?[^#]*)?(#.*)?/);
location.protocol = a[1] ? a[1] : "";
location.host = a[2] ? a[2] : "";
location.port = a[3] ? a[3] : "";
location.pathname = a[4] ? a[4] : "";
location.search = a[5] ? a[5] : "";
location.hash = a[6] ? a[6] : "";
location.hostname = location.host;
location.origin = location.protocol + "//" + location.host + (location.port ? ":" + location.port : "");
}
});
document.location = location
// 处理 localStorage 和 sessionStorage 的初始化
function Storage(){}
Storage.prototype.clear = function clear(){ console.log(' [Storage] clear'); var self = this; Object.keys(self).forEach(function (key) { self[key] = undefined; delete self[key]; }); }
Storage.prototype.getItem = function getItem(key){ var r = (this.hasOwnProperty(key)?String(this[key]):null); console.log(' [Storage] getItem',key,myparselog(r)); return r}
Storage.prototype.setItem = function setItem(key, val){ console.log(' [Storage] setItem',key,val); this[key] = (val === undefined)?null:String(val) }
Storage.prototype.key = function key(i){ console.log(' [Storage] key',i); return Object.keys(this)[i||0];}
Storage.prototype.removeItem = function removeItem(key){ console.log(' [Storage] removeItem',key); delete this[key];}
safefunction(Storage)
_storage_obj = new Storage
// window.localStorage
make_constructor("localStorage", "Storage", EN, EN, _storage_obj)
localStorage.__proto__["clear"] = safefunction(localStorage.__proto__["clear"]);
localStorage.__proto__["getItem"] = safefunction(localStorage.__proto__["getItem"]);
localStorage.__proto__["key"] = safefunction(localStorage.__proto__["key"]);
localStorage.__proto__["removeItem"] = safefunction(localStorage.__proto__["removeItem"]);
localStorage.__proto__["setItem"] = safefunction(localStorage.__proto__["setItem"]);
localStorage["__#classType"] = "localStorage";
Object.defineProperty(localStorage, 'length', { get: function(){ return Object.keys(this).length }, });
// window.sessionStorage
make_constructor("sessionStorage", "Storage", EN, EN, _storage_obj)
sessionStorage.__proto__["clear"] = safefunction(sessionStorage.__proto__["clear"]);
sessionStorage.__proto__["getItem"] = safefunction(sessionStorage.__proto__["getItem"]);
sessionStorage.__proto__["key"] = safefunction(sessionStorage.__proto__["key"]);
sessionStorage.__proto__["removeItem"] = safefunction(sessionStorage.__proto__["removeItem"]);
sessionStorage.__proto__["setItem"] = safefunction(sessionStorage.__proto__["setItem"]);
Object.defineProperty(sessionStorage, 'length', { get: function(){ return Object.keys(this).length }, });
// navigator.connection
make_constructor("_vconnect", "NetworkInformation", EN, EN)
navigator.connection = _vconnect
navigator.connection.__proto__["onchange"] = null;
navigator.connection.__proto__["effectiveType"] = "4g";
navigator.connection.__proto__["rtt"] = 50;
navigator.connection.__proto__["downlink"] = 10;
navigator.connection.__proto__["saveData"] = false;
// window.performance
make_constructor("performance", "Performance", EN, EN)
Object.assign(performance, {
"timeOrigin": 1619098076582.469,
"timing": {
"connectStart": 1619098076595,
"navigationStart": 1619098076582,
"loadEventEnd": 1619098077273,
"domLoading": 1619098076680,
"secureConnectionStart": 0,
"fetchStart": 1619098076595,
"domContentLoadedEventStart": 1619098077192,
"responseStart": 1619098076668,
"responseEnd": 1619098076878,
"domInteractive": 1619098077163,
"domainLookupEnd": 1619098076595,
"redirectStart": 0,
"requestStart": 1619098076602,
"unloadEventEnd": 1619098076678,
"unloadEventStart": 1619098076678,
"domComplete": 1619098077272,
"domainLookupStart": 1619098076595,
"loadEventStart": 1619098077272,
"domContentLoadedEventEnd": 1619098077196,
"redirectEnd": 0,
"connectEnd": 1619098076595
},
"navigation": {
"type": 0,
"redirectCount": 0
}
})
make_constructor("_vtiming", "PerformanceTiming", EN, EN)
make_constructor("_vnavigation", "PerformanceNavigation", EN, EN)
performance['timing'] = Object.assign(_vtiming, performance['timing'])
performance['navigation'] = Object.assign(_vnavigation, performance['navigation'])
// window.chrome
window.chrome = {
"app": {
"isInstalled": false,
"InstallState": { "DISABLED": "disabled", "INSTALLED": "installed", "NOT_INSTALLED": "not_installed" },
"RunningState": { "CANNOT_RUN": "cannot_run", "READY_TO_RUN": "ready_to_run", "RUNNING": "running" },
"getDetails": safefunction(function getDetails(){ console.log(" [chrome] getDetails")}),
"getIsInstalled": safefunction(function getIsInstalled(){ console.log(" [chrome] getIsInstalled")}),
"installState": safefunction(function installState(){ console.log(" [chrome] installState")}),
},
"runtime": {
"OnInstalledReason": { "CHROME_UPDATE": "chrome_update", "INSTALL": "install", "SHARED_MODULE_UPDATE": "shared_module_update", "UPDATE": "update" },
"OnRestartRequiredReason": { "APP_UPDATE": "app_update", "OS_UPDATE": "os_update", "PERIODIC": "periodic" },
"PlatformArch": { "ARM": "arm", "ARM64": "arm64", "MIPS": "mips", "MIPS64": "mips64", "X86_32": "x86-32", "X86_64": "x86-64" },
"PlatformNaclArch": { "ARM": "arm", "MIPS": "mips", "MIPS64": "mips64", "X86_32": "x86-32", "X86_64": "x86-64" },
"PlatformOs": { "ANDROID": "android", "CROS": "cros", "LINUX": "linux", "MAC": "mac", "OPENBSD": "openbsd", "WIN": "win" },
"RequestUpdateCheckStatus": { "NO_UPDATE": "no_update", "THROTTLED": "throttled", "UPDATE_AVAILABLE": "update_available" },
"connect": safefunction(function connect(){ console.log(" [chrome] connect") }),
"sendMessage": safefunction(function sendMessage(){ console.log(" [chrome] sendMessage") }),
"id": undefined,
}
}
// window.indexedDB
make_constructor("_vDOMStringList", "DOMStringList", [], EN, undefined, { allow_illegal: true})
make_constructor("_vIDBDatabase", "IDBDatabase", [], EN, undefined, { allow_illegal: true})
make_constructor("_vIDBOpenDBRequest", "IDBOpenDBRequest", [], EN, undefined, { allow_illegal: true})
make_constructor("indexedDB", "IDBFactory", EN, EN)
window.indexedDB.__proto__["cmp"] = function cmp(){_vLog('--- func(*) --- indexedDB.cmp');debugger;}; safefunction(window.indexedDB["cmp"]);
window.indexedDB.__proto__["databases"] = function databases(){_vLog('--- func(*) --- indexedDB.databases');debugger;}; safefunction(window.indexedDB["databases"]);
window.indexedDB.__proto__["deleteDatabase"] = function deleteDatabase(){_vLog('--- func(*) --- indexedDB.deleteDatabase');debugger;}; safefunction(window.indexedDB["deleteDatabase"]);
window.indexedDB.__proto__["open"] = function open(name){
var _temp_IDBOpenDBRequest = _vPxy(new IDBOpenDBRequest, 'IDBOpenDBRequest');
_temp_IDBOpenDBRequest.error = null
_temp_IDBOpenDBRequest.onblocked = null
_temp_IDBOpenDBRequest.onerror = null
_temp_IDBOpenDBRequest.onsuccess = null
_temp_IDBOpenDBRequest.onupgradeneeded = null
_temp_IDBOpenDBRequest.readyState = "done"
_temp_IDBOpenDBRequest.result = _vPxy(new IDBDatabase, 'IDBDatabase')
_temp_IDBOpenDBRequest.result.name = name
_temp_IDBOpenDBRequest.result.objectStoreNames = _vPxy(new DOMStringList, 'DOMStringList')
_temp_IDBOpenDBRequest.result.objectStoreNames.length = 0
_temp_IDBOpenDBRequest.result.onabort = null
_temp_IDBOpenDBRequest.result.onclose = null
_temp_IDBOpenDBRequest.result.onerror = null
_temp_IDBOpenDBRequest.result.onversionchange = null
_temp_IDBOpenDBRequest.result.version = 1
_temp_IDBOpenDBRequest.source = null
_temp_IDBOpenDBRequest.transaction = null
return _temp_IDBOpenDBRequest
}; safefunction(window.indexedDB["open"]);
// window.XMLHttpRequest
make_constructor("XMLHttpRequest", "XMLHttpRequest", EN, EN, undefined, { allow_illegal: true })
XMLHttpRequest.prototype["UNSENT"] = XMLHttpRequest["UNSENT"] = 0;
XMLHttpRequest.prototype["OPENED"] = XMLHttpRequest["OPENED"] = 1;
XMLHttpRequest.prototype["HEADERS_RECEIVED"] = XMLHttpRequest["HEADERS_RECEIVED"] = 2;
XMLHttpRequest.prototype["LOADING"] = XMLHttpRequest["LOADING"] = 3;
XMLHttpRequest.prototype["DONE"] = XMLHttpRequest["DONE"] = 4;
XMLHttpRequest.prototype["abort"] = function abort(){_vLog('--- func(*) --- XMLHttpRequest.abort');debugger;}; safefunction(XMLHttpRequest.prototype["abort"]);
XMLHttpRequest.prototype["getAllResponseHeaders"] = function getAllResponseHeaders(){_vLog('--- func(*) --- XMLHttpRequest.getAllResponseHeaders');debugger;}; safefunction(XMLHttpRequest.prototype["getAllResponseHeaders"]);
XMLHttpRequest.prototype["getResponseHeader"] = function getResponseHeader(){_vLog('--- func(*) --- XMLHttpRequest.getResponseHeader');debugger;}; safefunction(XMLHttpRequest.prototype["getResponseHeader"]);
XMLHttpRequest.prototype["open"] = function open(){_vLog('--- func(*) --- XMLHttpRequest.open');debugger;}; safefunction(XMLHttpRequest.prototype["open"]);
XMLHttpRequest.prototype["overrideMimeType"] = function overrideMimeType(){_vLog('--- func(*) --- XMLHttpRequest.overrideMimeType');debugger;}; safefunction(XMLHttpRequest.prototype["overrideMimeType"]);
XMLHttpRequest.prototype["send"] = function send(){_vLog('--- func(*) --- XMLHttpRequest.send');debugger;}; safefunction(XMLHttpRequest.prototype["send"]);
XMLHttpRequest.prototype["setRequestHeader"] = function setRequestHeader(){_vLog('--- func(*) --- XMLHttpRequest.setRequestHeader');debugger;}; safefunction(XMLHttpRequest.prototype["setRequestHeader"]);
// window.screen
make_constructor("screen", "Screen", EN, EN)
screen.__proto__["availWidth"] = 1920;
screen.__proto__["availHeight"] = 1040;
screen.__proto__["width"] = 1920;
screen.__proto__["height"] = 1080;
screen.__proto__["colorDepth"] = 24;
screen.__proto__["pixelDepth"] = 24;
screen.__proto__["availLeft"] = 0;
screen.__proto__["availTop"] = 0;
screen.__proto__["orientation"] = new (class ScreenOrientation {});
make_constructor("_vorientation", "ScreenOrientation", EN, EN)
_vorientation.__proto__["angle"] = 0;
_vorientation.__proto__["type"] = "landscape-primary";
_vorientation.__proto__["onchange"] = null;
_vorientation.__proto__["lock"] = function lock(){debugger;}; safefunction(_vorientation["lock"]);
_vorientation.__proto__["unlock"] = function unlock(){debugger;}; safefunction(_vorientation["unlock"]);
screen["orientation"] = _vorientation
// Element 元素上面通常存在的 style /CSSStyleDeclaration
make_constructor("_vCSSStyleDeclaration", "CSSStyleDeclaration", EN, EN)
function make_style() {
var style = Object.assign(new __cilame__['N']['CSSStyleDeclaration'], {
alignContent: "", alignItems: "", alignSelf: "", alignmentBaseline: "", all: "", animation: "", animationDelay: "", animationDirection: "", animationDuration: "", animationFillMode: "", animationIterationCount: "", animationName: "", animationPlayState: "", animationTimingFunction: "", appearance: "", ascentOverride: "", aspectRatio: "", backdropFilter: "",
backfaceVisibility: "",
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: "",
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: "",
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: "",
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: "",
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: "",
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: "",
x: "",
y: "",
zIndex: "",
zoom: "",
})
style.__proto__ = safefunction(function(){})
return style
}
// document.createElement , 这个函数很重要,需要特殊挂钩一下
var htmlmap = {
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"],
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"],
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"],
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"]
}
// 临时的 canvas 附加,让 canvas 至少能跑通
function attach_canvas(ele){
ele.getContext = safefunction(function getContext(){console.log(' [document.createElement.getContext] []');
var v = _vPxy(new class WebGLRenderingContext{
createBuffer(){ console.log(' [document.createElement.WebGLRenderingContext.createBuffer]', ...arguments); return _vPxy(new class WebGLBuffer{}, 'WebGLBuffer') }
createProgram(){ console.log(' [document.createElement.WebGLRenderingContext.createProgram]', ...arguments); return _vPxy(new class WebGLProgram{}, 'WebGLProgram') }
createShader(){ console.log(' [document.createElement.WebGLRenderingContext.createShader]', ...arguments); return _vPxy(new class WebGLShader{}, 'WebGLShader') }
fillText(){ console.log(' [document.createElement.WebGLRenderingContext.fillText]', ...arguments) }
fillRect(){ console.log(' [document.createElement.WebGLRenderingContext.fillRect]', ...arguments) }
bindBuffer(){ console.log(' [document.createElement.WebGLRenderingContext.bindBuffer]', ...arguments) }
bufferData(){ console.log(' [document.createElement.WebGLRenderingContext.bufferData]', ...arguments) }
shaderSource(){ console.log(' [document.createElement.WebGLRenderingContext.shaderSource]', ...arguments) }
compileShader(){ console.log(' [document.createElement.WebGLRenderingContext.compileShader]', ...arguments) }
attachShader(){ console.log(' [document.createElement.WebGLRenderingContext.attachShader]', ...arguments) }
linkProgram(){ console.log(' [document.createElement.WebGLRenderingContext.linkProgram]', ...arguments) }
useProgram(){ console.log(' [document.createElement.WebGLRenderingContext.useProgram]', ...arguments) }
getAttribLocation(){ console.log(' [document.createElement.WebGLRenderingContext.getAttribLocation]', ...arguments) }
getUniformLocation(){ console.log(' [document.createElement.WebGLRenderingContext.getUniformLocation]', ...arguments) }
enableVertexAttribArray(){ console.log(' [document.createElement.WebGLRenderingContext.enableVertexAttribArray]', ...arguments) }
vertexAttribPointer(){ console.log(' [document.createElement.WebGLRenderingContext.vertexAttribPointer]', ...arguments) }
uniform2f(){ console.log(' [document.createElement.WebGLRenderingContext.uniform2f]', ...arguments) }
drawArrays(){ console.log(' [document.createElement.WebGLRenderingContext.drawArrays]', ...arguments) }
getSupportedExtensions(){ console.log(' [document.createElement.WebGLRenderingContext.getSupportedExtensions]', ...arguments) }
}, "WebGLRenderingContext")
v.ARRAY_BUFFER = 34962
v.STATIC_DRAW = 35044
v.VERTEX_SHADER = 35633
v.FLOAT = 5126
v.canvas = _vPxy(new class HTMLCanvasElement{
toDataURL(){
console.log(' [document.createElement.WebGLRenderingContext.canvas.HTMLCanvasElement.toDataURL]', ...arguments)
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"
}
}, "document.createElement.WebGLRenderingContext.canvas.HTMLCanvasElement")
return v
})
ele.toDataURL = safefunction(function toDataURL(){
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"
})
}
document.createElement = safefunction(function createElement(e){
var ostart = start
var ostart1 = start1
if (ostart){ console.log(' [document.createElement]', e) }
start = false
start1 = false
var htmlmapkeys = Object.keys(htmlmap)
e = e.toLocaleLowerCase()
for (var i = 0; i < htmlmapkeys.length; i++) {
if (htmlmap[htmlmapkeys[i]].indexOf(e) != -1){
var ele = eval(` _vPxy(new class ${htmlmapkeys[i]}{}, "${htmlmapkeys[i]}");`)
break
}
}
if (!ele){ var ele = eval(` _vPxy(new class HTMLElement{}, "HTMLElement");`) }
ele.getAttribute = safefunction(function getAttribute(N){ console.log(' [document.createElement.getAttribute] null',N); return null})
ele.getAttributeNode = safefunction(function getAttributeNode(N){ console.log(' [document.createElement.getAttributeNode] null',N); return null})
ele.getAttributeNames = safefunction(function getAttributeNames(N){ console.log(' [document.createElement.getAttributeNames] []',N); return []})
ele.getElementsByClassName = safefunction(function getElementsByClassName(N){ console.log(' [document.createElement.getElementsByClassName] []',N); return []})
ele.getElementsByTagName = safefunction(function getElementsByTagName(N){ console.log(' [document.createElement.getElementsByTagName] []',N); return []})
ele.getElementsByTagNameNS = safefunction(function getElementsByTagNameNS(A,B){ console.log(' [document.createElement.getElementsByTagNameNS] []',A,B); return []})
if (e == 'canvas'){
attach_canvas(ele)
}
ele.style = make_style()
start = ostart
start1 = ostart1
return ele
})
// mimeTypes模拟
make_constructor("_vPlugin", "Plugin", EN, EN, Array)
make_constructor("_vMimeType", "MimeType", EN, EN)
make_constructor("_vMimeTypeArray", "MimeTypeArray", EN, EN, Array)
_vMimeTypeArray[0] = new __cilame__['N']['MimeType']
_vMimeTypeArray[0].description = ""
_vMimeTypeArray[0].enabledPlugin = new __cilame__['N']['Plugin']
_vMimeTypeArray[0].enabledPlugin[0] = _vMimeTypeArray[0]
_vMimeTypeArray[0].enabledPlugin.description = ""
_vMimeTypeArray[0].enabledPlugin.filename = "mhjfbmdgcfjbbpaeojofohoefgiehjai"
_vMimeTypeArray[0].enabledPlugin.length = 1
_vMimeTypeArray[0].enabledPlugin.name = "Chrome PDF Viewer"
_vMimeTypeArray[0].suffixes = "pdf"
_vMimeTypeArray[0].type = "application/pdf"
_vMimeTypeArray[_vMimeTypeArray[0].type] = _vMimeTypeArray[0]
_vMimeTypeArray[1] = new __cilame__['N']['MimeType']
_vMimeTypeArray[1].description = "Portable Document Format"
_vMimeTypeArray[1].enabledPlugin = new __cilame__['N']['Plugin']
_vMimeTypeArray[1].enabledPlugin[0] = _vMimeTypeArray[1]
_vMimeTypeArray[1].enabledPlugin.description = "Portable Document Format"
_vMimeTypeArray[1].enabledPlugin.filename = "internal-pdf-viewer"
_vMimeTypeArray[1].enabledPlugin.length = 1
_vMimeTypeArray[1].enabledPlugin.name = "Chrome PDF Viewer"
_vMimeTypeArray[1].suffixes = "pdf"
_vMimeTypeArray[1].type = "application/x-google-chrome-pdf"
_vMimeTypeArray[_vMimeTypeArray[1].type] = _vMimeTypeArray[1]
_vMimeTypeArray[2] = new __cilame__['N']['MimeType']
_vMimeTypeArray[2].description = "Native Client Executable"
_vMimeTypeArray[2].enabledPlugin = new __cilame__['N']['Plugin']
_vMimeTypeArray[2].enabledPlugin[0] = _vMimeTypeArray[2]
_vMimeTypeArray[2].enabledPlugin[1] = _vMimeTypeArray[3]
_vMimeTypeArray[2].enabledPlugin.description = ""
_vMimeTypeArray[2].enabledPlugin.filename = "internal-nacl-plugin"
_vMimeTypeArray[2].enabledPlugin.length = 2
_vMimeTypeArray[2].enabledPlugin.name = "Native Client"
_vMimeTypeArray[2].suffixes = "pdf"
_vMimeTypeArray[2].type = "application/x-nacl"
_vMimeTypeArray[_vMimeTypeArray[2].type] = _vMimeTypeArray[2]
_vMimeTypeArray[3] = new __cilame__['N']['MimeType']
_vMimeTypeArray[3].description = "Portable Native Client Executable"
_vMimeTypeArray[3].enabledPlugin = new __cilame__['N']['Plugin']
_vMimeTypeArray[3].enabledPlugin[0] = _vMimeTypeArray[2]
_vMimeTypeArray[3].enabledPlugin[1] = _vMimeTypeArray[3]
_vMimeTypeArray[3].enabledPlugin.description = ""
_vMimeTypeArray[3].enabledPlugin.filename = "internal-nacl-plugin"
_vMimeTypeArray[3].enabledPlugin.length = 2
_vMimeTypeArray[3].enabledPlugin.name = "Native Client"
_vMimeTypeArray[3].suffixes = "pdf"
_vMimeTypeArray[3].type = "application/x-pnacl"
_vMimeTypeArray[_vMimeTypeArray[3].type] = _vMimeTypeArray[3]
Object.defineProperty(_vMimeTypeArray, 'length', { get: function(){ return 4 } })
navigator.mimeTypes = _vMimeTypeArray
// 电池信息模拟
make_constructor("_vBatteryManager", "BatteryManager", EN, EN)
BatteryManager.prototype['charging'] = true
BatteryManager.prototype['chargingTime'] = 0
BatteryManager.prototype['dischargingTime'] = Infinity
BatteryManager.prototype['level'] = 1
BatteryManager.prototype['onchargingchange'] = null
BatteryManager.prototype['onchargingtimechange'] = null
BatteryManager.prototype['ondischargingtimechange'] = null
BatteryManager.prototype['onlevelchange'] = null
navigator.getBattery = safefunction(function getBattery(){
var ostart = start
start = false
fakePromise = new safefunction_with_name(function Promise(){}, 'Promise') // 这里不用真实的 Promise 主要就是考虑到更好的控制执行流程
fakePromise.then = safefunction(function then(func){
EventTarget.prototype.addEventListener('load', function(){
return func(_vPxy(_vBatteryManager, "BatteryManager"))
})
})
start = ostart
return fakePromise
})
// runloads: 在你添加的js执行完之后,再执行这个用于将 load 内的函数尽数执行
;(typeof global=='undefined'?window:global).runloads = function runloads(reverse){
var loadfuncs = EventTarget.prototype.listeners.load
var T = '======================================================================='
if (loadfuncs){
if (reverse){
for (var i = loadfuncs.length - 1; i >= 0; i--) {
console.log(`${T} LoadFunc ${loadfuncs[i].name||'UnknownFunc'} ${T}`)
loadfuncs[i]() }
}else{
for (var i = 0; i < loadfuncs.length; i++) {
console.log(`${T} LoadFunc ${loadfuncs[i].name||'UnknownFunc'} ${T}`)
loadfuncs[i]()
}
}
}
}
// 用于生成代码用,在环境中无影响,保留即可
var nn = Object.keys(__cilame__['n'])
var NN = Object.keys(__cilame__['N'])
var AA = ['addEventListener', 'dispatchEvent', 'removeEventListener', 'clientInformation']
return nn.concat(NN).concat(AA)
}
Cilame()
// console.log(localStorage)
// console.log(localStorage.length)
// console.log(localStorage.getItem("$_fb"))
// console.log(localStorage.removeItem("$_fb"))
// console.log(localStorage.getItem("$_fb"))
// console.log(localStorage)
// console.log(localStorage.setItem("$_fb", "hahaha"))
// console.log(localStorage.getItem("$_fb"))
// console.log(localStorage)
// sessionStorage.__proto__["length"] = 2;
// sessionStorage.__proto__["clear"] = function clear(){debugger;}; safefunction(sessionStorage.__proto__["clear"]);
// sessionStorage.__proto__["getItem"] = function getItem(){debugger;}; safefunction(sessionStorage.__proto__["getItem"]);
// sessionStorage.__proto__["key"] = function key(){debugger;}; safefunction(sessionStorage.__proto__["key"]);
// sessionStorage.__proto__["removeItem"] = function removeItem(){debugger;}; safefunction(sessionStorage.__proto__["removeItem"]);
// sessionStorage.__proto__["setItem"] = function setItem(){debugger;}; safefunction(sessionStorage.__proto__["setItem"]);
// sessionStorage["$_cDro"] = "1";
// sessionStorage["$_YWTU"] = "FEQUsSBVzv0QWk6YXiwmU1rTQu5fgYnAS0QCjp2noTZ";
// console.log(1,window)
// console.log(1,window.constructor)
// console.log(2,window.__proto__)
// console.log(2,window.__proto__.constructor)
// console.log(3,window.__proto__.__proto__)
// console.log(3,window.__proto__.__proto__.constructor)
// console.log(4,window.__proto__.__proto__.__proto__)
// console.log(4,window.__proto__.__proto__.__proto__.constructor)
// console.log()
// console.log(5,navigator)
// console.log(5,navigator.constructor)
// console.log(6,navigator.__proto__)
// console.log(6,navigator.__proto__.constructor)
// console.log(7,navigator.__proto__.__proto__)
// console.log(7,navigator.__proto__.__proto__.constructor)
// console.log()
// console.log(7,document)
// console.log(7,document.constructor)
// console.log(8,document.__proto__)
// console.log(8,document.__proto__.constructor)
// console.log(9,document.__proto__.__proto__)
// console.log(9,document.__proto__.__proto__.constructor)
// console.log(10,document.__proto__.__proto__.__proto__)
// console.log(10,document.__proto__.__proto__.__proto__.constructor)
// console.log(11,document.__proto__.__proto__.__proto__.__proto__)
// console.log(11,document.__proto__.__proto__.__proto__.__proto__.constructor)
================================================
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t5补环境框架.md
================================================
# 补环境框架
补环境框架可以帮助代码在接近原始环境的条件下执行,相当于前面模板的组合加强版。
---
## js-sandbox-env-framework
[https://github.com/lasawang/js-sandbox-env-framework](https://github.com/lasawang/js-sandbox-env-framework)
一个完整的 JavaScript 浏览器环境模拟框架,支持 在线编辑、Proxy 递归代理、环境注入、AI 辅助补环境等功能,专为 JS 逆向工程设计。
---
## NodeSandbox
一个基于 jsdom 的沙箱环境,可以。
[https://github.com/bnmgh1/NodeSandbox](https://github.com/bnmgh1/NodeSandbox)
---
## qxVm
[https://github.com/ylw00/qxVm](https://github.com/ylw00/qxVm)
基于 `node16`, `vm2`模块, 纯js设计一个补环境框架。
---
## egg\_vm2
[https://github.com/theheqiang/egg\_vm2](https://github.com/theheqiang/egg_vm2)
使用 Node.js 中的 vm2 实现一个简单的浏览器环境。
---
## jsVMEnv
[https://github.com/ipylei/jsVmEnv](https://github.com/ipylei/jsVmEnv)
================================================
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.3 selenium环境模拟/readme.md
================================================
## 补不了就用浏览器
补环境是指用于在**非浏览器环境**下模拟浏览器运行 JavaScript 的工具。但是实在补不出来也不能一直耗着浪费时间,那就不补了,直接用浏览器环境执行代码。
常用方式 playwright+express+核心JS文件,部署一个持久运行的浏览器实例服务,供远程调用执行JS代码。
例如:
```js
/* eslint-disable */
import { createCipheriv } from 'crypto';
import { devices, chromium } from 'playwright-chromium';
const iPhone11 = devices['iPhone 11 Pro'];
import path from 'path';
import { fileURLToPath } from 'url';
function getRandomInt(a, b) {
const min = Math.min(a, b);
const max = Math.max(a, b);
const diff = max - min + 1;
return min + Math.floor(Math.random() * Math.floor(diff));
}
class Signer {
static instance = null;
userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36';
args = [
'--disable-blink-features',
'--disable-blink-features=AutomationControlled',
'--disable-infobars',
'--window-size=1920,1080',
'--start-maximized',
];
// Default TikTok loading page
default_url = 'https://www.tiktok.com/@aisarkhaledd';
// Password for xttparams AES encryption
password = 'webapp1.0+202106';
constructor(default_url, userAgent, browser) {
if (default_url) {
this.default_url = default_url;
}
if (userAgent) {
this.userAgent = userAgent;
}
if (browser) {
this.browser = browser;
this.isExternalBrowser = true;
}
this.args.push(`--user-agent='${this.userAgent}'`);
this.options = {
headless: true,
args: this.args,
ignoreDefaultArgs: ['--mute-audio', '--hide-scrollbars'],
ignoreHTTPSErrors: true
};
this.isInitialized = false;
}
static async getInstance() {
if (!Signer.instance) {
Signer.instance = new Signer();
await Signer.instance.init();
}
return Signer.instance;
}
static async close() {
if (Signer.instance) {
await Signer.instance.close();
Signer.instance = null;
}
}
async init() {
if (this.isInitialized) {
return;
}
// Get the directory name of the current module
const __dirname = path.dirname(fileURLToPath(import.meta.url));
if (!this.browser) {
this.browser = await chromium.launch(this.options);
}
let emulateTemplate = {
...iPhone11,
locale: 'en-US',
deviceScaleFactor: getRandomInt(1, 3),
isMobile: Math.random() > 0.5,
hasTouch: Math.random() > 0.5,
userAgent: this.userAgent,
};
emulateTemplate.viewport.width = getRandomInt(320, 1920);
emulateTemplate.viewport.height = getRandomInt(320, 1920);
this.context = await this.browser.newContext({
bypassCSP: true,
...emulateTemplate,
});
this.page = await this.context.newPage();
await this.page.route('**/*', (route) => {
return route.request().resourceType() === 'script'
? route.abort()
: route.continue();
});
await this.page.goto(this.default_url, {
waitUntil: 'networkidle',
});
let LOAD_SCRIPTS = ['webmssdk_5.1.3.js',];
LOAD_SCRIPTS.forEach(async (script) => {
await this.page.addScriptTag({
path: path.resolve(__dirname, script),
});
console.log('[+] ' + script + ' loaded');
});
await this.page.evaluate(() => {
window.generateXBogus = function generateXBogus(query, undf) {
if (typeof window.__tsign.u[970].v !== 'function') {
throw 'No X-Bogus function found';
}
return window.__tsign.u[970].v(query, undf);
};
window.generateXGnarly = function generateXGnarly(query, strBody,baseUrl) {
if (typeof window.__tsign.u[971].v !== 'function') {
throw 'No X-Gnarly function found';
}
const p4 = {
"totalXHRRequests": 70,
"totalFetchRequests": 25,
"interceptedXHRRequests": 8,
"interceptedFetchRequests": 6
}
return window.__tsign.u[971].v(query, strBody,baseUrl,p4);
};
return this;
});
this.isInitialized = true;
console.log('[+] Signer initialized successfully');
}
async navigator() {
// Get the 'viewport' of the page, as reported by the page.
const info = await this.page.evaluate(() => {
return {
deviceScaleFactor: window.devicePixelRatio,
userAgent: window.navigator.userAgent,
browser_language: window.navigator.language,
browser_platform: window.navigator.platform,
browser_name: window.navigator.appCodeName,
browser_version: window.navigator.appVersion,
};
});
return info;
}
async Sign({ url, body = '' }) {
//console.log('Sign', { e: url, t: body });
const params = new URL(url).search.slice(1); // removes the "?" from the start
const xGnarly = await this.page.evaluate(`generateXGnarly('${params}', ${body || 'null'},'${url}')`);
const xBogus = await this.page.evaluate(`generateXBogus('${params}', ${null})`);
return { signedUrl:`${url}&X-Bogus=${xBogus}&X-Gnarly=${xGnarly}`, xBogus, xGnarly }
}
xttparams(query_str) {
query_str += '&is_encryption=1';
// Encrypt query string using aes-128-cbc
const cipher = createCipheriv('aes-128-cbc', this.password, this.password);
return Buffer.concat([cipher.update(query_str), cipher.final()]).toString(
'base64'
);
}
async healthCheck() {
if (!this.isInitialized || !this.page) {
return false;
}
try {
await this.page.evaluate(() => {
return typeof window.generateXBogus === 'function' && typeof window.generateXGnarly === 'function';
});
return true;
} catch (error) {
console.error('Health check failed:', error);
return false;
}
}
async close() {
if (this.browser && !this.isExternalBrowser) {
await this.browser.close();
this.browser = null;
}
if (this.page) {
this.page = null;
}
this.isInitialized = false;
}
}
export default Signer;
// Export singleton functions for easier use
export const getSigner = () => Signer.getInstance();
export const closeSigner = () => Signer.close();
```
用python库来开发也可以,但是在部署在linux中时往往会有依赖问题,不如playwright官方提供的mcr.microsoft.com/playwright:v1.50.0-noble ,可快速部署。
| 框架名称 | 描述 | 是否支持 DOM | 是否支持浏览器 API | 是否支持 WebAssembly | 是否支持动态执行 |
| --- | --- | --- | --- | --- | --- |
| [Node.js + JSDOM](https://github.com/jsdom/jsdom) | 在 Node.js 中模拟浏览器环境 | ✅ | ❌(部分支持) | ❌ | ✅ |
| \[Node.js + CJS / ESM 模块模拟\] | 手动补环境(最常用) | ❌ | ❌ | ❌ | ✅ |
| [Puppeteer](https://pptr.dev/) | 基于 Chrome DevTools 的控制工具 | ✅ | ✅ | ✅ | ✅ |
| [Playwright](https://playwright.dev/) | 多浏览器自动化工具(支持 Chromium/Firefox/Webkit) | ✅ | ✅ | ✅ | ✅ |
| [Selenium](https://www.selenium.dev/) | 经典的浏览器自动化框架 | ✅ | ✅ | ✅ | ✅ |
================================================
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.3 selenium环境模拟/test.py
================================================
# -*- coding: utf-8 -*-
import os
from selenium import webdriver
ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...'
PRO_DIR = os.path.dirname(os.path.abspath(__file__))
s1 = """
signature-hook
"""
def driver_sig(html_file):
option = webdriver.ChromeOptions()
option.add_argument('headless')
option.add_argument('--no-sandbox')
option.add_argument('--user-agent={}'.format(ua))
driver = webdriver.Chrome(chrome_options=option)
driver.get('file:///'+ PRO_DIR + html_file)
sig = driver.title
driver.quit()
return sig
sign_js = '''
window.navigator = {
userAgent: ''
};
function get_sign() {
... //此处省略N行代码
return sign
}
var signature = get_sign();
document.clear();
document.write(signature);
'''
if __name__ == '__main__':
doc = sign_js.replace("userAgent: ''","userAgent: '{}'".format(ua))
html_file = 'get_sign.html'
with open(html_file, 'w', encoding='utf-8') as fw:
fw.write(s1 + doc + s2)
sig = driver_sig(html_file)
print(sig)
================================================
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/readme.md
================================================
# 背景
## 一、什么是“补环境”?
在 JavaScript 逆向中,“补环境”指的是**在非浏览器环境中模拟或还原浏览器运行 JavaScript 所需的上下文环境**,以便能够让目标 JavaScript 脚本正常执行。
简单来说,就是**构建一个浏览器的“假环境”**,让被逆向的 JS 代码以为它是在浏览器中运行,从而可以顺利执行并输出我们需要的结果。
所以“补环境”是 WebJS 逆向中的核心技能之一,它是连接爬虫与前端加密逻辑的重要桥梁。
掌握补环境技术,不仅可以提升逆向分析能力,还能帮助开发者更好地理解浏览器机制和 JS 执行原理。
---
## 二、为什么需要“补环境”?
JavaScript 代码通常是在浏览器环境中运行的,依赖于浏览器提供的各种全局对象(如 `window`、`document`、`navigator`)和内置函数(如 `fetch`、`XMLHttpRequest`、`setTimeout`)等。
但当我们使用 Node.js、Python 的 `execjs`、`Pyppeteer`、`Playwright` 或者一些沙盒工具来执行网页中的 JS 代码时,这些环境并不具备浏览器完整的执行上下文,导致 JS 代码无法正常运行,甚至直接报错。
---
## 三、补环境的原理
JavaScript 是一种动态语言,其运行依赖于当前的执行环境。在浏览器中,JS 代码可以访问一系列全局对象和函数,比如:
* `window`
* `document`
* `location`
* `navigator`
* `history`
* `localStorage`
* `sessionStorage`
* `XMLHttpRequest`
* `fetch`
* `setTimeout` / `setInterval`
在非浏览器环境中,这些对象和函数可能缺失或功能不全。补环境的核心原理就是:
1. **手动或自动模拟缺失的全局对象和函数**
2. **拦截和重写关键函数,使其返回预期结果**
3. **绕过环境检测机制(如 navigator.webdriver、proto 等)**
---
## 四、补环境的常见方法
### 1. 手动补环境
适用于小型 JS 代码或对性能要求不高的场景。
**示例:**
```javascript
// 手动补 window 和 document
var window = {};
var document = {
cookie: "",
createElement: function() {
return {};
}
};
```
### 2. 使用浏览器模拟工具(如 Puppeteer、Playwright)
这些工具启动一个无头浏览器,自动提供完整的执行环境,适合需要复杂交互的场景。
```javascript
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
const result = await page.evaluate(() => {
return someFunction(); // 在浏览器环境中执行
});
console.log(result);
await browser.close();
})();
```
### 3. 使用沙盒工具 + 环境模拟库(如 jsdom、happy-dom)
这些库可以在 Node.js 环境中模拟 DOM 和浏览器 API。
```javascript
const { JSDOM } = require('jsdom');
const dom = new JSDOM(`Hello world
`);
global.window = dom.window;
global.document = dom.window.document;
```
### 4. 使用逆向工具(如 Hook、调试器)
在补环境时,可以使用调试器(如 Chrome DevTools、Frida、Hook.js)来动态分析 JS 代码,找出关键函数和环境检测点,进行模拟或绕过。
---
## 五、补环境的难点
1. **环境检测复杂化**:网站可能使用多重检测手段,如 `Function.toString()`、`Proxy`、`WebAssembly` 等。
2. **依赖浏览器特性**:某些 JS 代码依赖浏览器渲染引擎(如 Canvas、WebGL)生成特定值。
3. **性能问题**:使用 Puppeteer 等完整浏览器模拟时,资源消耗较大。
4. **加密代码混淆**:JS 代码被混淆后难以理解,补环境难度加大。
================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.0 加密方法远程调用/readme.md
================================================
加密方法的远程调用主要是使用了RPC协议,RPC(Remote Procedure Call)是远程调用的意思。RPC的应用十分广泛,比如在分布式中的进程间通讯、微服务中的节点通讯。
我们这里使用的rpc其实是实现两个不同进程通信的一种方式,比如在浏览器执行一些方法,将结果返回给本地使用。
在JS逆向这块,不论是selenium、cefpython、puppeteer或者其他工具都可以实现。
大家可以按照书中的案例进行练习。
此文件夹中会更新一些新的案例供大家学习。
================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.0 加密方法远程调用/头条系web-RPC.md
================================================
以头条系某短视频(dy)web页面搜索为例,通过RPC的逻辑实现数据采集。
目前方案通用于头条系web页面。因为其当前产品大都基于XMLHttpRequest的send方法做一些校验,我们可以自启一个浏览器去完成XMLHttpRequest请求,直接获取返回的responseText。
话虽如此,此方案仅是为了配合书中的教程供大家学习,并不代表是最优选择,主要是给大家提供一种思路和方法。
代码逻辑很简单,只有50行代码,有不懂的问题可私信或留言。
更多精彩内容:[《爬虫逆向进阶实战》](http://t.csdn.cn/mEa64)
---
## 调试分析
因受版权影响,我会避开关键词。
先找一下其发送逻辑,堆栈第一个点进去。

断点后调试,可看到t即是XMLHttpRequest。

查看t对象。

在浏览器中调试。

查看响应。 当前已经返回了responseText和带了签名的responseURL。

---
## Python实现
注意:url要换成自己浏览器上的。
```python
# -*- coding: utf-8 -*-
# @UpdataTime : 2022/6/1 16:00
# @Author : lx
from selenium import webdriver
class Browser():
def __init__(self, **kwargs):
# TODO: update your executablePath
executablePath = r"chromedriver.exe"
self.executablePath = kwargs.get("executablePath",executablePath )
options = webdriver.ChromeOptions()
self.browser = webdriver.Chrome(executable_path=self.executablePath, chrome_options=options)
self.browser.get('https://www.douyin.com')
def search_item(self, keyword):
doc = self.browser.execute_script('''
function queryData(url) {
var p = new Promise(function(resolve,reject) {
var e={
"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",
"method":"GET"
};
var h = new XMLHttpRequest;
h.open(e.method, e.url, true);
h.setRequestHeader("accept","application/json, text/plain, */*");
h.setRequestHeader("salute-by","lx");
h.setRequestHeader("content-type","application/json;charset=UTF-8");
h.onreadystatechange =function() {
if(h.readyState === 4 && h.status ===200) {
resolve(h.responseText);
} else {}
};
h.send(null);
});
return p;
}
var p1 = queryData('lx');
res = Promise.all([p1]).then(function(result){
return result
})
return res
''' % (keyword))
return doc[0]
def close(self):
self.browser.close()
self.browser.quit()
browser = Browser()
# 注意:如果没打印内容,把url换成自己浏览器上的。还不行就在控制台上执行js看是否有误。
# 版本 102.0.5005.63(正式版本) (64 位)
print(browser.search_item('爬虫逆向进阶实战'))
print(browser.search_item('RPC'))
print(browser.search_item('案例'))
print(browser.search_item('教程'))
print(browser.search_item('公众号'))
print(browser.search_item('pythonlx'))
browser.close()
```
---
## 执行结果

================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.1 微博登陆参数RPC/client.js
================================================
!function(){
if (window.flagLX){}
else{
window.weiboLx = makeRequest;
var ws = new WebSocket("ws://127.0.0.1:9999");
window.flagLX =true;
ws.open = function(evt){};
ws.onmessage = function(evt){
var lx = evt.data;
var result = lx.split(",");
var res = window.weiboLx(result[0],result[1],7,false);
ws.send(JSON.stringify(res));
}}
}();
================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.1 微博登陆参数RPC/server.py
================================================
import asyncio
import websockets
import time
async def check_permit(websocket):
# 账号列表
for send_text in [
'11111111111,111',
'11111111112,112',
'11111111113,113',
'11111111114,114'
]:
await websocket.send(send_text)
return True
async def recv_msg(websocket):
while 1:
recv_text = await websocket.recv()
print(recv_text)
async def main_logic(websocket, path):
await check_permit(websocket)
await recv_msg(websocket)
start_server = websockets.serve(main_logic, '127.0.0.1', 9999)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/2022-05-25更新.md
================================================
## update: 2022-05-25
本文内容是继之前失效文章的补充。 RPC的方法大家应该都从书中掌握了。 (虽然官网更新了,但是没有掌握的还可以看一下视频)
所以长话短说,本篇的内容是找新版本弹幕wss协议的RPC的入口点,并进行RPC调用。

---
## 定位
在JS中,websocket 的 new WebSocket() 是固定的语法,可以用做我们定位的关键词。
webSocket.send 用于向服务器发送数据
webSocket.onopen 用于指定连接成功后的回调函数
webSocket.onmessage 用于指定收到服务器数据后的回调函数
webSocket.onclose 用于指定连接关闭后的回调函数
websocket.binaryType = 'arraybuffer'; 用来表示通用的、固定长度的原始二进制数据缓冲区
---
RPC最重要的是找到入口点。一般消息处理函数为onmessage 或者 addEventListener("message")
```js
ws.onmessage = function(event) {
var data = event.data;
};
ws.addEventListener("message", function(event) {
var data = event.data;
});
```
全局检索一下,找到this.client.addEventListener("message"

断点往下走,进入bindClientMessage

o = n.Response.deserializeBinary
顾名思义,o是响应内容反序列化的二进制,控制台打印下,可以看到关键词WebcastSocialMessage。

继续往下看代码,if ("msg" === t.getPayloadType() , (()=>o.toObject()))

现在已经能看到一些明文信息了,但是payload的内容似乎经过base64。
atob一下试试,可以看出这是protobuf序列化后的数据。

所以打好断点继续调试。

走到runAllEvents中,发现了protobuf反序列化后的数据。

---
找到位置后,还是用之前的RPC方法即可。

把数据发送到本地。

---
## RPC调用
通过wss协议发数据。

把发数据的代码加上,然后在本地起一个服务端。
```python
import asyncio
import websockets
async def check_permit(websocket):
send_text = 'lx'
await websocket.send(send_text)
return True
async def recv_msg(websocket):
while 1:
recv_text = await websocket.recv()
print(recv_text)
async def main_logic(websocket, path):
await check_permit(websocket)
await recv_msg(websocket)
start_server = websockets.serve(main_logic, '127.0.0.1', 9999)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
```
---
运行测试,大功告成!

只要大家只要掌握到方法,无论网站怎么改都能从容面对。
================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/client.js
================================================
// 这是当前新版的
window.dataLx = s.toObject();
!function(){
var res = window.dataLx;
if (window.flagLX){
window.wsLX.send(JSON.stringify(res));
}
else{
var ws = new WebSocket("ws://127.0.0.1:9999");
window.wsLX = ws;
window.flagLX = true;
ws.open = function(evt){};
ws.onmessage = function(evt){
ws.send(JSON.stringify(res));
}
}
}();
// 这是视频中老版本的
window.dataLx = r;
!function(){
var res = window.dataLx;
if (window.flagLX){
window.wsLX.send(JSON.stringify(res));
}
else{
var ws = new WebSocket("ws://127.0.0.1:9999");
window.wsLX = ws;
window.flagLX =true;
ws.open = function(evt){};
ws.onmessage = function(evt){
ws.send(JSON.stringify(res));
}}
}();
================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/readme.md
================================================
1、更新内容在 2022-05-25更新.md 中
2、更新的视频在 https://www.bilibili.com/video/BV1o34y1L7RX/
================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/server.py
================================================
import asyncio
import websockets
async def check_permit(websocket):
send_text = 'lx'
await websocket.send(send_text)
return True
async def recv_msg(websocket):
while 1:
recv_text = await websocket.recv()
print(recv_text)
async def main_logic(websocket, path):
await check_permit(websocket)
await recv_msg(websocket)
start_server = websockets.serve(main_logic, '127.0.0.1', 9999)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index20231108.py
================================================
import json
from selenium import webdriver
class Browser():
def __init__(self, **kwargs, ):
self.debug = kwargs.get("debug", False)
self.proxy = kwargs.get("proxy", None)
self.api_url = kwargs.get("api_url", None)
self.referrer = kwargs.get("referer", "https://trendinsight.oceanengine.com/")
# TODO: update your executablePath
self.executablePath = kwargs.get("executablePath", r"C:\Users\lx\Desktop\driver\chromedriver.exe")
args = kwargs.get("browser_args", [])
options = kwargs.get("browser_options", {})
if len(args) == 0:
self.args = []
else:
self.args = args
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("log-level=2")
self.options = {
#"headless": True,
"handleSIGINT": True,
"handleSIGTERM": True,
"handleSIGHUP": True,
}
if self.proxy is not None:
if "@" in self.proxy:
server_prefix = self.proxy.split("://")[0]
address = self.proxy.split("@")[1]
self.options["proxy"] = {
"server": server_prefix + "://" + address,
"username": self.proxy.split("://")[1].split(":")[0],
"password": self.proxy.split("://")[1].split("@")[0].split(":")[1],
}
else:
self.options["proxy"] = {"server": self.proxy}
if self.executablePath is not None:
self.options["executablePath"] = self.executablePath
self.browser = webdriver.Chrome(executable_path=self.executablePath, chrome_options=options)
self.browser.get('https://trendinsight.oceanengine.com/arithmetic-index')
for k, v in cks.items():
self.browser.add_cookie({"name": k, "value": v})
self.browser.refresh()
def signature(self, keyword, start_date, end_date):
sign_url = self.browser.execute_script('''
function queryData(url) {
var p = new Promise(function(resolve,reject) {
var e={"url":"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend",
"method":"POST",
"data" : '{"keyword_list": ["%s"],"start_date": "%s","end_date": "%s","app_name": "aweme"}'};
var h = new XMLHttpRequest;h.open(e.method, e.url, true);
h.setRequestHeader("accept","application/json, text/plain, */*");
h.setRequestHeader("content-type","application/json;charset=UTF-8");
h.setRequestHeader("tea-uid","7054893410171930123");
h.onreadystatechange =function() {
if(h.readyState != 4) return;
if(h.readyState === 4 && h.status ===200) {
resolve(h.responseText);
} else {
}
};
h.send(e.data);
});
return p;
}
var p1 = queryData('lx');
res = Promise.all([p1]).then(function(result){
return result
})
return res;
''' % (keyword, start_date, end_date))
'''
let e={"url":"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend",
"method":"POST",
"data" : '{"keyword_list":["lx"],"start_date":"20220430","end_date":"20220530","app_name":"aweme"}'};
var h = new XMLHttpRequest;h.open(e.method, e.url, true);
h.setRequestHeader("accept","application/json, text/plain, */*");
h.setRequestHeader("content-type","application/json;charset=UTF-8");
h.setRequestHeader("tea-uid","7054893410171930123");
h.onreadystatechange=function(){
if (h.status===200){
console.log(h.responseText)
console.log(h.responseURL)
}
}
h.send(e.data);
'''
return sign_url[0]
def decrypt(self,data):
text = self.browser.execute_script('''
function d(e) {
var t = e ;
var n = atob(t);
var r = new Uint8Array(n.length);
for (var i = 0; i < n.length; i++) {
r[i] = n.charCodeAt(i);
}
return r;
}
var text = "%s";
var key = "kbSjOqn9O7APLqUZxdCkTQ==";
var iv = "JuhL1cOV5JH9ojzt2g2EPg==";
async function decrypt(text,key,iv) {
var t = d(key);
var i = d(iv);
var r = await window.crypto.subtle.importKey("raw", t, "AES-CBC", !0, ["decrypt"]);
var result = await window.crypto.subtle.decrypt({
name: "AES-CBC",
iv: i
}, r, d(text));
result = (new TextDecoder()).decode(result)
return result
}
function getResult(){
var p = decrypt(text,key,iv);
return Promise.all([p]).then(data=>{
console.log(data)
return data[0]
})
}
var p1 = getResult();
res = Promise.all([p1]).then(function(result){
return result
})
return res
'''%data)
return text[0]
def responseText(self, keyword, start_date, end_date):
doc = self.browser.execute_script('''
function queryData(url) {
var p = new Promise(function(resolve,reject) {
var e={"url":"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend",
"method":"POST",
"data" : '{"keyword_list": ["%s"],"start_date": "%s","end_date": "%s","app_name": "aweme"}'};
var h = new XMLHttpRequest;h.open(e.method, e.url, true);
h.setRequestHeader("accept","application/json, text/plain, */*");
h.setRequestHeader("content-type","application/json;charset=UTF-8");
h.setRequestHeader("tea-uid","7054893410171930123");
h.onreadystatechange =function() {
if(h.readyState != 4) return;
if(h.readyState === 4 && h.status ===200) {
resolve(h.responseText);
} else {
}
};
h.send(e.data);
});
return p;
}
var p1 = queryData('lx');
res = Promise.all([p1]).then(function(result){
return result
})
return res;
''' % (keyword, start_date, end_date))
return doc[0]
def close(self):
self.browser.close()
self.browser.quit()
def get_data(keyword, start_date, end_date):
text = browser.signature(keyword=keyword, start_date=start_date, end_date=end_date)
data = json.loads(text)['data']
doc = browser.decrypt(data)
return doc
if __name__ == '__main__':
cookies = "" # "把你登录后的cookie复制到这里"
cks = {}
for k in cookies.split(';'):
c = k.split('=')
cks[c[0].replace(' ','')] = c[1]
browser = Browser()
print(get_data(keyword='lx', start_date="20231106", end_date="20231107"))
print(get_data(keyword='鞠婧祎', start_date="20231106", end_date="20231107"))
browser.close()
================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index_0.py
================================================
# -*- coding: utf-8 -*-
# @Time : 2021/9/27 14:46
# @Author : lx
from selenium import webdriver
from lxpy import copy_headers_dict
import requests
h = copy_headers_dict('''
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cache-control: no-cache
content-length: 89
content-type: application/json;charset=UTF-8
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
origin: https://trendinsight.oceanengine.com
pragma: no-cache
referer: https://trendinsight.oceanengine.com/arithmetic-index/analysis?keyword=lx
sec-ch-ua: "Google Chrome";v="93", " Not;A Brand";v="99", "Chromium";v="93"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-origin
tea-uid: 6945252828761294374
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
''')
class Browser():
def __init__(self, **kwargs, ):
self.debug = kwargs.get("debug", False)
self.proxy = kwargs.get("proxy", None)
self.api_url = kwargs.get("api_url", None)
self.referrer = kwargs.get("referer", "https://trendinsight.oceanengine.com/")
# TODO: update your executablePath
self.executablePath = kwargs.get("executablePath", r"C:\Users\feiyi\Desktop\driver\chromedriver.exe")
args = kwargs.get("browser_args", [])
options = kwargs.get("browser_options", {})
if len(args) == 0:
self.args = []
else:
self.args = args
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("log-level=2")
self.options = {
"headless": True,
"handleSIGINT": True,
"handleSIGTERM": True,
"handleSIGHUP": True,
}
if self.proxy is not None:
if "@" in self.proxy:
server_prefix = self.proxy.split("://")[0]
address = self.proxy.split("@")[1]
self.options["proxy"] = {
"server": server_prefix + "://" + address,
"username": self.proxy.split("://")[1].split(":")[0],
"password": self.proxy.split("://")[1].split("@")[0].split(":")[1],
}
else:
self.options["proxy"] = {"server": self.proxy}
if self.executablePath is not None:
self.options["executablePath"] = self.executablePath
self.browser = webdriver.Chrome(executable_path=self.executablePath, chrome_options=options)
self.browser.get('https://trendinsight.oceanengine.com/arithmetic-index')
def signature(self, keyword, start_date, end_date):
sign_url = self.browser.execute_script('''
var e={"url":"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend",
"method":"POST",
"data" : '{"keyword_list": ["%s"],"start_date": "%s","end_date": "%s","app_name": "aweme"}'};
var h = new XMLHttpRequest;h.open(e.method, e.url, true);
h.setRequestHeader("accept","application/json, text/plain, */*");
h.setRequestHeader("content-type","application/json;charset=UTF-8");
h.send(e.data);
return h._url
''' % (keyword, start_date, end_date))
return sign_url
def close(self):
self.browser.close()
self.browser.quit()
def get_data(keyword, start_date, end_date):
data = '{"keyword_list": ["%s"],"start_date": "%s","end_date": "%s","app_name": "aweme"}' % (
keyword, start_date, end_date)
sign_url = browser.signature(keyword=keyword, start_date=start_date, end_date=end_date)
print(sign_url)
doc = requests.post(sign_url, headers=h, data=data.encode()).json()['data']
return doc
import base64
from Crypto.Cipher import AES
# AES-128
def decrtptlx(String):
iv = "amlheW91LHFpYW53".encode(encoding='utf-8')
key = 'anN2bXA2NjYsamlh'.encode(encoding='utf-8')
cryptor = AES.new(key=key, mode=AES.MODE_CFB, IV=iv, segment_size=128)
decode = base64.b64decode(String)
plain_text = cryptor.decrypt(decode)
print(plain_text)
return plain_text
browser = Browser()
# test
decrtptlx(get_data(keyword='lx', start_date="20210826", end_date="20210926"))
# test
decrtptlx(get_data(keyword = '鞠婧祎',start_date = "20210826",end_date = "20210926"))
# 需要修改driver-path
browser.close()
================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index_1.py
================================================
# -*- coding: utf-8 -*-
import json
from selenium import webdriver
from lxpy import copy_headers_dict
h = copy_headers_dict('''
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cache-control: no-cache
content-length: 89
content-type: application/json;charset=UTF-8
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
origin: https://trendinsight.oceanengine.com
pragma: no-cache
referer: https://trendinsight.oceanengine.com/arithmetic-index/analysis?keyword=lx
sec-ch-ua: "Google Chrome";v="93", " Not;A Brand";v="99", "Chromium";v="93"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-origin
tea-uid: 6945252828761294374
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
''')
class Browser():
def __init__(self, **kwargs, ):
self.debug = kwargs.get("debug", False)
self.proxy = kwargs.get("proxy", None)
self.api_url = kwargs.get("api_url", None)
self.referrer = kwargs.get("referer", "https://trendinsight.oceanengine.com/")
# TODO: update your executablePath
self.executablePath = kwargs.get("executablePath", r"chromedriver.exe")
args = kwargs.get("browser_args", [])
options = kwargs.get("browser_options", {})
if len(args) == 0:
self.args = []
else:
self.args = args
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("log-level=2")
self.options = {
"headless": True,
"handleSIGINT": True,
"handleSIGTERM": True,
"handleSIGHUP": True,
}
if self.proxy is not None:
if "@" in self.proxy:
server_prefix = self.proxy.split("://")[0]
address = self.proxy.split("@")[1]
self.options["proxy"] = {
"server": server_prefix + "://" + address,
"username": self.proxy.split("://")[1].split(":")[0],
"password": self.proxy.split("://")[1].split("@")[0].split(":")[1],
}
else:
self.options["proxy"] = {"server": self.proxy}
if self.executablePath is not None:
self.options["executablePath"] = self.executablePath
self.browser = webdriver.Chrome(executable_path=self.executablePath, chrome_options=options)
self.browser.get('https://trendinsight.oceanengine.com/arithmetic-index')
def signature(self, keyword, start_date, end_date):
sign_url = self.browser.execute_script('''
function queryData(url) {
var p = new Promise(function(resolve,reject) {
var e={"url":"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend",
"method":"POST",
"data" : '{"keyword_list": ["%s"],"start_date": "%s","end_date": "%s","app_name": "aweme"}'};
var h = new XMLHttpRequest;h.open(e.method, e.url, true);
h.setRequestHeader("accept","application/json, text/plain, */*");
h.setRequestHeader("content-type","application/json;charset=UTF-8");
h.setRequestHeader("tea-uid","7054893410171930123");
h.onreadystatechange =function() {
if(h.readyState != 4) return;
if(h.readyState === 4 && h.status ===200) {
resolve(h.responseText);
} else {
}
};
h.send(e.data);
});
return p;
}
var p1 = queryData('lx');
res = Promise.all([p1]).then(function(result){
return result
})
return res;
''' % (keyword, start_date, end_date))
'''
let e={"url":"https://trendinsight.oceanengine.com/api/open/index/get_multi_keyword_hot_trend",
"method":"POST",
"data" : '{"keyword_list":["lx"],"start_date":"20220430","end_date":"20220530","app_name":"aweme"}'};
var h = new XMLHttpRequest;h.open(e.method, e.url, true);
h.setRequestHeader("accept","application/json, text/plain, */*");
h.setRequestHeader("content-type","application/json;charset=UTF-8");
h.setRequestHeader("tea-uid","7054893410171930123");
h.onreadystatechange=function(){
if (h.status===200){
console.log(h.responseText)
console.log(h.responseURL)
}
}
h.send(e.data);
'''
return sign_url[0]
def close(self):
self.browser.close()
self.browser.quit()
def get_data(keyword, start_date, end_date):
data = '{"keyword_list": ["%s"],"start_date": "%s","end_date": "%s","app_name": "aweme"}' % (keyword, start_date, end_date)
data = browser.signature(keyword=keyword, start_date=start_date, end_date=end_date)
doc = json.loads(data)['data']
return doc
import base64
from Crypto.Cipher import AES
# AES-128
def decrtptlx(String):
iv = "amlheW91LHFpYW53".encode(encoding='utf-8')
key = 'anN2bXA2NjYsamlh'.encode(encoding='utf-8')
cryptor = AES.new(key=key, mode=AES.MODE_CFB, IV=iv, segment_size=128)
decode = base64.b64decode(String)
plain_text = cryptor.decrypt(decode)
print(plain_text)
return plain_text
browser = Browser()
# test
decrtptlx(get_data(keyword='lx', start_date="20210826", end_date="20210926"))
# test
decrtptlx(get_data(keyword = '鞠婧祎',start_date = "20210826",end_date = "20210926"))
browser.close()
================================================
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/readme.md
================================================
(TODO:之前的版本失效了,大家查看最近提交的文件,旧版可作为参考)
对RPC来讲,需要找可调用的方法入口,像头条系这种在send后重写url的,可以通过查找xmlhttprequest堆栈来定位。

找到h.onreadystatechange,可知h就是xmlhttprequest对象.在控制台输出可以看到responseURL中生成了带签名的url。

所以我们按照书中方法,进行模拟执行即可。 (可以看视频教程有助理解)
代码中需要安装的依赖库: requests、lxpy、selenium、Crypto
Crypto库下载链接:https://pan.baidu.com/s/1xOg9qKWNsMfmWuT20Gf9FA?pwd=9999
================================================
FILE: 第九章:安卓逆向案例/9.0 书外新增案例/cntvnews.md
================================================
base64: 5aSu6KeG5paw6Ze7YXBw
# 版本9.2.0
标准HMACSHA256加密,算法助手pro即可分析。
## x-emas-gw-sign参数
`emas_gw_utdid`:aVaQIP4xdkADAGQcvpa5LIuC
`emas_gw_ttid`:1618388776598@CCNews\_Android\_10.11.0
`fe`:先对params按key排序,&拼接键值对,生成md5哈希值。
`c` :c = str(round(time.time()))
hmac msg: `f'{emas_gw_utdid}&&&20000008&{fe}&{c}&emas.feed.iflow.server.getchannelitems&1.0.0&&{emas_gw_ttid}&&&27'`
hmac key:3df8017cb9367f5997ab9e4b19c1e028
================================================
FILE: 第九章:安卓逆向案例/9.0 书外新增案例/readme.md
================================================
以文章内容展示,给大家分享在逆向过程中遇到的一些签名和加密参数。
================================================
FILE: 第九章:安卓逆向案例/9.0 书外新增案例/凤凰新闻app.md
================================================
# 凤凰新闻app
# 版本7.38.0
## 接口
nine.ifeng.com/wemediacontentlist
## 脱壳
腾讯加固:com.tencent.StubShell.TxAppEntry
通过反射大师,断网脱壳,导出dex。(用别的也行)
## sn参数
一些字符串拼接后MD5,盐值在so中: "acF%#\*{\_b1mQt@..ifvy"

## sn生成代码
```js
import random
import time
import hashlib
v = "7.38.0"
proid = "ifengnews"
publishid = "2899"
deviceid = "v001iVTYiFTMlBjM2IWM0EGM40QYgfr3r340gf"
so = "acF%#*{_b1mQt@..ifvy"
r = int((random.random() * 8999) + 1000)
timec = str(int(time.time()))
st = f"{timec}{r}"
sn_str = f'{v}{proid}{publishid}{deviceid}{st}{so}'
sn = hashlib.md5(sn_str.encode(encoding='utf-8')).hexdigest()
print(st)
print(sn)
```
================================================
FILE: 第九章:安卓逆向案例/9.0 书外新增案例/趣头条sign.md
================================================
案例内容:趣头条app的sign值分析和生成。
案例环境:趣头条(v3.10.43.000.0603.1931)、夜神模拟器(安卓5)、Frida(12.11.18)、Unidbg(0.9.5)
> 声明:文章内容仅供参考学习,如有侵权请联系作者进行删除。
---
@[toc]
---
## 接口分析

url: "http://39.107.213.234/search/searchContentNew"
params:
```json
{
"dtu": "003",
"tk": "ACH5kAjk7kEzhC-JcKT27sgVQw5V2TuYW0Q0NzUxNDk1MDg5NTIyNQ",
"lon": "0.0",
"token": "",
"guid": "ee4d8ab62051306258de31e88ec1.04506739",
"uuid": "ba4be62de1e14e14a80f64e9e1ef42f3",
"tuid": "-ZAI5O5BM4QviXCk9u7IFQ",
"tabCode": "0",
"oaid": "",
"distinct_id": "d81d2cf27a955ec6",
"version": "31043000",
"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",
"traceId": "94c370c5a88283dafd2f235f29a7762a",
"keywordSource": "hotword",
"page": "1",
"deviceCode": "863064707522829",
"limit": "20.0",
"sign": "02ebb2d129c354762e6a4083cb17b05d",
"time": "1649991315231",
"h5_zip_version": "1004",
"versionName": "3.10.43.000.0603.1931",
"network": "wifi",
"OSVersion": "5.1.1",
"searchSource": "0",
"innoseed": "",
"device_code": "863064707522829",
"lat": "0.0"
}
```
经过简单的测试,发现params中的参数都不能缺少。说明服务端对这些都进行了校验,那么直接在源码中检索这些关键词定位即可。

经过一顿找,hook了几个位置,确定了在com.jifen.framework.http.napi.util.d中。

hook看看参数和参数值

包名:com.jifen.qukan
版本:8.1.0
---
## Frida Hook
```python
import frida, sys
def on_message(message, data):
print("[%s] => %s" % (message, data))
session = frida.get_usb_device().attach('com.jifen.qukan')
js_code = """
Java.perform(function(){
console.log("1 start hook");
var ba = Java.use('com.jifen.framework.http.napi.util.d');
if (ba){
console.log("2 find class");
ba.c.implementation = function(a1){
console.log("3 find method");
console.log(a1);
var res = ba.a(a1)
console.log(res);
return res;
}
}
})
"""
script = session.create_script(js_code)
script.on('message', on_message)
script.load()
sys.stdin.read()
```
打印结果:

参数是list,把params的参数转为 {key=value}后添加在数组中。
在函数中把list转换为了字符串,并且进行了排序。
返回的结果中则生成了sign。

所以最终的计算在NativeUtils.getInnoSoInfo(sb.substring(0, sb.length() - 1));

可以看到最终是执行了native String innoSign(String str) ,接下来继续HOOK getInnoSoInfo方法。
```python
js_code = """
Java.perform(function(){
console.log("1 start hook");
var ba = Java.use('com.jifen.qukan.utils.NativeUtils');
if (ba){
console.log("2 find class");
ba.getInnoSoInfo.implementation = function(a1){
console.log("3 find method");
console.log(a1);
var res = ba.getInnoSoInfo(a1)
console.log(res);
return res;
}
}
})
"""
```
打印结果:

计算的参数已经知晓,通过在线网站生成的md5值和返回的结果不同,说明参数在so中进行了处理。
那我们去NativeExample.so中看看innoSign方法。
---
## So分析
找到NativeExample.so。

拿IDA反汇编。

搜索innoSign。

双击innoSign进入后F5查看伪代码。

innoSign()内容如下:
```c
int __fastcall innoSign(const char *a1)
{
const char *v1; // r6
char *v2; // r4
int v3; // r0
size_t v4; // r0
char *v5; // r5
size_t v6; // r0
size_t v7; // r0
char *v8; // r4
int result; // r0
int v10; // [sp+48h] [bp-78h]
int v11; // [sp+4Ch] [bp-74h]
int v12; // [sp+50h] [bp-70h]
int v13; // [sp+54h] [bp-6Ch]
int v14; // [sp+58h] [bp-68h]
int v15; // [sp+5Ch] [bp-64h]
unsigned __int8 v16; // [sp+A0h] [bp-20h]
unsigned __int8 v17; // [sp+A1h] [bp-1Fh]
unsigned __int8 v18; // [sp+A2h] [bp-1Eh]
unsigned __int8 v19; // [sp+A3h] [bp-1Dh]
unsigned __int8 v20; // [sp+A4h] [bp-1Ch]
unsigned __int8 v21; // [sp+A5h] [bp-1Bh]
unsigned __int8 v22; // [sp+A6h] [bp-1Ah]
unsigned __int8 v23; // [sp+A7h] [bp-19h]
unsigned __int8 v24; // [sp+A8h] [bp-18h]
unsigned __int8 v25; // [sp+A9h] [bp-17h]
unsigned __int8 v26; // [sp+AAh] [bp-16h]
unsigned __int8 v27; // [sp+ABh] [bp-15h]
unsigned __int8 v28; // [sp+ACh] [bp-14h]
unsigned __int8 v29; // [sp+ADh] [bp-13h]
unsigned __int8 v30; // [sp+AEh] [bp-12h]
unsigned __int8 v31; // [sp+AFh] [bp-11h]
int v32; // [sp+B0h] [bp-10h]
v1 = a1;
v2 = malloc(0x11u);
_aeabi_memclr();
v3 = 0;
do
{
v2[v3] = byte_3648[v3] ^ byte_3658[v3];
++v3;
}
while ( v3 != 16 );
v4 = strlen(v1);
v5 = malloc(v4 + 512);
strcpy(v5, v1);
v6 = strlen(v5);
*&v5[v6] = 2036689702;
*&v5[v6 + 4] = 61;
strcat(v5, v2);
v10 = 0;
v11 = 0;
v12 = 1732584193;
v13 = -271733879;
v14 = -1732584194;
v15 = 271733878;
v7 = strlen(v5);
j_MD5Update(&v10, v5, v7);
j_MD5Final(&v10, &v16);
free(v5);
free(v2);
v8 = malloc(0x21u);
sprintf(
v8,
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
v16,
v17,
v18,
v19,
v20,
v21,
v22,
v23,
v24,
v25,
v26,
v27,
v28,
v29,
v30,
v31,
v19,
v18,
v17,
v16,
v10,
v11,
v12,
v13,
v14,
v15);
result = _stack_chk_guard - v32;
if ( _stack_chk_guard == v32 )
result = v8;
return result;
}
```
简单看了一下,最后返回了result。result = _stack_chk_guard - v32;if ( _stack_chk_guard == v32 ) result = v8;
_stack_chk_guard 是检查栈帧是否溢出,检查数据是否被修改。
不往下追了,后面还有很多内容。接下来通过unidbg来调so的方法。
---
## Unidbg调用
先搭个架子执行下看看是否需要补环境,路径自己改一改。
```java
package com.jni;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.memory.Memory;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class qutoutiao extends AbstractJni {
private final AndroidEmulator emulator;
private final VM vm;
private Module module;
String rootPath = "C:\\Users\\Desktop\\AppTest\\";
File apkFile = new File(rootPath+"趣头条.apk");
File soFile = new File(rootPath+"libNativeExample.so");
// OtoB: Object to Bytes;
private static byte[] OtoB(Object obj){
try {
ByteArrayOutputStream ByteStream = new ByteArrayOutputStream();
ObjectOutputStream ObjectStream = new ObjectOutputStream(ByteStream);
ObjectStream.writeObject(obj);
ObjectStream.flush();
byte[] newArray = ByteStream.toByteArray();
ObjectStream.close();
ByteStream.close();
return newArray;
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
public qutoutiao() {
emulator = AndroidEmulatorBuilder.for32Bit().build();
final Memory memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
vm = emulator.createDalvikVM(apkFile);
vm.setVerbose(false);
vm.setJni(this);
DalvikModule dm = vm.loadLibrary(soFile, true);
module = dm.getModule();
dm.callJNI_OnLoad(emulator);
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
try {
emulator.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}));
}
public String get_sign(){
DvmClass BitmapkitUtils = vm.resolveClass("com/jifen/qukan/utils/NativeUtils");
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";
StringObject signs = BitmapkitUtils.callStaticJniMethodObject(emulator,"innoSign()",params);
String sign = signs.getValue();
return sign;
}
public static void main(String[] args) {
com.jni.qutoutiao qtt = new com.jni.qutoutiao();
System.out.println(qtt.get_sign());
}
}
```
用frida hook的参数和Unidbg执行结果进行对比。

发现两者一致。

继续抓包对比下。将数据包params的sign删除后按key排序生成新字符串,放到unidbg中执行。生成的sign和返回的一致。

那么本节案例到此结束了,大家动手操作一遍!
---

================================================
FILE: 第九章:安卓逆向案例/9.0 书外新增案例/飞瓜sign.md
================================================
本文案例是飞瓜APP的Sign参数分析和生成。
> 声明:文章内容仅供参考学习,如有侵权请联系作者进行删除。
---
## 接口分析
观察后发现,同一时间请求的不同接口,Sign是相同的。

API:"http://appapi.feigua.cn/api/v1/live/liveRealtimeRoomDataV3?page=1&pattern=2&pageSize=5"
headers:
```
{
Platform Android
Imei 161174e6-6db5-42e9-8569-63f815042db1
Version 148-1.4.8
LoginType
LoginId
ts 1647493831
Sign 198C5C37675D494DAEDCE494389300C6
Host appapi.feigua.cn
Accept-Encoding gzip
User-Agent okhttp/3.12.0
Connection keep-alive
}
```
---
## 参数定位
定位比较简单

点进去看看

builder2.addHeader("Sign", HttpConstant.m22288a(hashMap, d, sb3.toString()));
先看看参数
sb3 = System.currentTimeMillis() / 1000;
String d = SharedPreferencesUtils.m22806b(MyApplication.m22275b()).m22809d(SessionId);
再看一下 HttpConstant.m22288a

就是把stringBuffer 各种拼接、排序处理后, md5一下。

java代码很简单,静态分析结束,为了保险起见,hook md5看看参数吧。
---
## Hook调试

Frida代码:
```python
# -*- coding: utf-8 -*-
# @Author : lx
# @IDE :PyCharm
import frida, sys
def on_message(message, data):
print("[%s] => %s" % (message, data))
session = frida.get_usb_device().attach('com.feigua.androiddy')
js_code = '''
Java.perform(
function(){
console.log("1. start hook");
var ba = Java.use("com.feigua.androiddy.d.i");
if (ba != undefined) {
console.log("2. find class");
ba.a.implementation = function(a1){
console.log("3. hook method");
console.log(a1);
var res = ba.a(a1);
console.log(res);
return res
}
}
}
)
'''
script = session.create_script(js_code)
script.on('message', on_message)
script.load()
sys.stdin.read()
```
接着先看是不是正常的MD5,经对比一样的。

分析完了,拿python还原一下。
---
## python还原
Imei 可以不带 ,代码如下:
```python
# -*- coding: utf-8 -*-
# @Time : 2022/3/17 13:28
# @Author : lx
# @IDE :PyCharm
import requests
import time
import hashlib
headers = {
"Platform":"Android",
# "Imei":"161174e6-6db5-42e9-8569-63f815042db1",
"Version":"148-1.4.8",
"LoginType":"",
"LoginId":"",
"Host":"appapi.feigua.cn",
"Accept-Encoding":"gzip",
"User-Agent":"okhttp/3.12.0",
"Connection":"keep-alive",
}
def get_md5(string):
m = hashlib.md5()
m.update(string.encode())
return m.hexdigest()
ts = str(round(time.time()))
# 最好直接根据key从小到大 排序
item = {
"page":"1",
"pagesize":"5",
"pattern":"2",
"platform":"Android",
"ts":ts
}
params=sorted(item.items(),key=lambda x:x[0])
sb = "CCd35181!!6445btrrtBBertert==="
for p in params:
sb += "&"
sb += f'{p[0]}={p[1]}'
print(sb)
sign = get_md5(sb).upper()
print(sign)
headers.update({"ts":ts})
headers.update({"Sign":sign})
res = requests.get("http://appapi.feigua.cn/api/v1/live/liveRealtimeRoomDataV3?page=1&pattern=2&pageSize=5",headers=headers)
print(res.text)
```
好了,到这里就结束了。
================================================
FILE: 第九章:安卓逆向案例/9.1 某新闻加密参数分析和还原/frida1.py
================================================
import frida, sys
def on_message(message, data):
print("[%s] => %s" % (message, data))
session = frida.get_usb_device().attach('cn.dahebao')
jscode_hook = """
Java.perform(
function(){
console.log("1. start hook");
var ba = Java.use("com.dingduan.lib_network.interceptor.CommonParamInterceptor").$new();
if (ba != undefined) {
console.log("2. find class");
ba.md5.implementation = function (a1) {
console.log("3. find function");
console.log(a1);
var res = ba.md5(a1);
console.log("计算Sign:" + res);
return res;
}
}
}
)
"""
script = session.create_script(jscode_hook)
script.on('message', on_message)
script.load()
sys.stdin.read()
================================================
FILE: 第九章:安卓逆向案例/9.2 某瓣签名Frida还原/frida1.py
================================================
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
jscode_hook = """
Java.perform(
function(){
console.log("1. start hook");
var ba = Java.use("com.douban.frodo.utils.crypto.HMACHash1");
if (ba != undefined) {
console.log("2. find class");
ba.a.overload('java.lang.String', 'java.lang.String').implementation = function (a1,a2) {
console.log("3. find function");
console.log(a1);
console.log(a2);
var res = ba.a(a1,a2);
console.log("计算result:" + res);
return res;
}
}
}
)
"""
process = frida.get_usb_device().attach('com.douban.frodo')
script = process.create_script(jscode_hook)
script.on('message', on_message)
print('[*] Hook Start Running')
script.load()
sys.stdin.read()
================================================
FILE: 第九章:安卓逆向案例/9.2 某瓣签名Frida还原/run.py
================================================
import requests,time
from urllib.parse import quote,urlparse
import hashlib,base64,hmac
headers = {"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"}
def bd_request():
url = ""
ts = str(round(time.time()))
params ={
'count':'30',
'tag':'追剧',
'os_rom':'miui6',
'apikey':'0dad551ec0f84ed02907ff5c42e8ec70',
'channel':'Baidu_Market',
'udid':'bba04d59bdf9c91ef59ff80573c4480c1a661a70',
'timezone':'Asia/Shanghai',
"_sig": get_sig(url=url, ts=ts),
"_ts": ts,
}
data = requests.get(url, params=params, headers=headers).text
return data
def get_sig(url,ts):
urlpath = urlparse(url).path
sign = '&'.join(['GET', quote(urlpath,safe=''), ts])
sig = hmac.new("bf7dddc7c9cfe6f7".encode(), sign.encode(), hashlib.sha1).digest()
_sig = base64.b64encode(sig).decode()
return _sig
print(bd_request())
================================================
FILE: 第九章:安卓逆向案例/9.4 某图参数Frida+Flask RPC/run.py
================================================
import frida
from flask import Flask, jsonify, request
app = Flask(__name__)
def on_message(message, data):
print("[%s] => %s" % (message, data))
def start_hook():
session = frida.get_usb_device().attach('com.mt.mtxx.mtxx')
js_code = '''
rpc.exports = {
"a": function (kw) {
var ret = {};
Java.perform(function(){
var SigEntity = Java.use("com.meitu.secret.SigEntity");
var BaseApplication = Java.use('com.meitu.library.application.BaseApplication');
var str1 = "search/feeds.json";
var str3 = "6184556633574670337";
var content = BaseApplication.getApplication();
var result = SigEntity.generatorSig(str1, kw, str3, content);
ret["result"]=result.sig.value;
console.log("[*] Sig:",result.sig.value);
}
)
return ret;
}
}
'''
script = session.create_script(js_code)
script.on('message', on_message)
script.load()
return script
@app.route("/hook")
def search():
kw = request.args.get("kw")
# 因参数过长,此处代码中的params不完整
params = ['1639127762948', 'CMCC', 'GMT+8',kw, ...]
result = start_hook().exports.a(params)
return jsonify({'result':result})
if __name__ == '__main__':
app.run()
================================================
FILE: 第九章:安卓逆向案例/9.5 某东加密参数Unidbg生成/readme.md
================================================
**案例 9.3也在其中**
**lxServer**: 是书中对某东APP的sign参数分析和通过Unidbg模拟调用.
**unidbg-jd-sign-11**:新增的,是对11版本的调用。
- 运行前准备好java环境以及maven
- 按照readme中的说明修改路径和测试
================================================
FILE: 第九章:安卓逆向案例/9.6 某资讯加固脱壳和参数分析/hook.py
================================================
import frida, sys
def on_message(message, data):
print("[%s] => %s" % (message, data))
session = frida.get_usb_device().attach('com.hipu.yidian')
jscode_hook = """
Java.perform(
function(){
console.log("1. start hook");
var ba = Java.use("com.yidian.news.util.sign.SignUtil");
if (ba != undefined) {
console.log("2. find class");
ba.signInternal.implementation = function (a1,a2) {
console.log("3. find function");
console.log(a1);
console.log(a2);
var res = ba.signInternal(a1,a2);
console.log("计算Sign:" + res);
return res;
}
}
}
)
"""
script = session.create_script(jscode_hook)
script.on('message', on_message)
script.load()
sys.stdin.read()
================================================
FILE: 第九章:安卓逆向案例/9.6 某资讯加固脱壳和参数分析/rpc.py
================================================
import frida
def on_message(message, data):
print("[%s] => %s" % (message, data))
def start_hook():
session = frida.get_usb_device().attach('com.hipu.yidian')
print("[*] start hook")
js_code = '''
rpc.exports = {
"a": function (params) {
var ret = {};
Java.perform(function(){
console.log("1. start hook");
var ba = Java.use("com.yidian.news.util.sign.SignUtil");
var current_application = Java.use('android.app.ActivityThread').currentApplication();
var a1 = current_application.getApplicationContext();
if (ba != undefined) {
console.log("2. find class");
var a2 = params;
var res = ba.signInternal(a1,a2);
console.log("计算Sign:" + res);
console.log(res)
ret["result"]=res;
console.log(ret)
}
}
)
return ret;
}
}
'''
script = session.create_script(js_code)
script.on('message', on_message)
script.load()
return script
import time
stimec = str(int(time.time() * 1000))
params = f'yidian6.0.4.41kbylz0sj_{stimec}_207030300'
result = start_hook().exports.a(params)
print(result)
================================================
FILE: 第八章:抓包技巧汇总/heytap软件商店抓包.md
================================================
本文内容是 heytap软件商店抓包案例。
---
用常规的http/https工具,比如charles、fiddler去抓包时,无法正常对heytapmobi进行抓包。
会提示客户端SSL握手失败,Received fatal alert: certificate_unknown

本以为是双向认证的原因,但是并没找到有效的客户端证书,所以开始通过其他工具进行抓包。
拿httpCanary试过,并没有拦截到。
经过一番测试发现使用NetKeeper可解决问题。
---
**NetKeeper抓包精灵** 不需要ROOT,通过抓包的结果还能抓取音频以及视频。
设置一下过滤条件,方便查看数据包。

触发评论请求后,成功看到数据包。
https://api-cn.store.heytapmobi.com:443/common/v1/comment/list?appId=3700438&size=10&start=40&token=-1&type=bad
**Type类型:** hot、good、middle、bad

可以发现有加密参数sign。
抓到包后,后面的操作就不再多说了,大家自行研究。
---
我在源码中也直接搜索过comment相关api,通过hook一些类也能拿到数据接口。
================================================
FILE: 第八章:抓包技巧汇总/readme.md
================================================
对应第八章《八:抓包技巧汇总》
大家先把书中概念性的东西了解一下
书中出现的内容就不重复贴了,这里加一些案例和知识点,持续更新
================================================
FILE: 第八章:抓包技巧汇总/夜神安卓7导入charles证书.md
================================================
夜神安卓7系统的charles证书导入。由于用户安装的外部证书不被信任,所以需要把SSL证书安装到安卓系统证书目录里。
---
## 一:下载证书
开启本地代理,在浏览器输入 chls.pro/ssl 下载证书到本地。
把证书原名charles-proxy-ssl-proxying-certificate.pem 先修改为 charles.pem
---
## 二:打印证书
通过openssl输出证书内容,自行安装openssl
下载地址:[https://slproweb.com/products/Win32OpenSSL.html](https://slproweb.com/products/Win32OpenSSL.html)
安装后通过 openssl command 打开command。

输入 `openssl x509 -inform PEM -subject_hash_old -in charles.pem`
执行后打印的结果中,第一行的90e59ded复制一下。

此处把证书名修改为 90e59ded.0 。 注意格式,你修改为 xxx.0
---
## 三:导入设备
不管啥方法,把证书传进设备的 /sdcard/ 文件下。
可以通过adb push,命令: `adb push xxx.0 /sdcard/`
然后进入adb shell中,adb shell 连接手机,不是root的通过命令 su 切换下,然后cd到 /sdcard/中。

没问题的话将证书移动到 /system/etc/security/cacerts/ 路径下。
命令: `mv xxx.0 /system/etc/security/cacerts/`

有可能会执行失败,说只读之类的Read-only file system
可以先执行命令:`mount -o rw,remount /system`
或者执行命令:`mount -o rw,remount /`
然后再mv移动。
---
## 四:证书授权
给证书权限的执行命令:`chmod 777 /system/etc/security/cacerts/xxx.0`
重启手机:`reboot`
证书导入完成,配置下wifi代理就可以正常抓包了。
================================================
FILE: 第八章:抓包技巧汇总/快手app抓包.md
================================================
# 快手app抓包
快手app版本8+往后使用的quic协议。QUIC 基于 UDP 传输、多数代理工具不支持,且快手用 Aegon 库强制 QUIC、同时叠加证书校验与代理绕过机制,导致常规代理抓包失效。
最常用的解决方法是将app的quic协议降级成http/https协议。
## 背景
快手的 QUIC 逻辑全部封装在自研的 `Aegon` 网络库中。
1. 把快手 APK 拖入 Jadx-Gui,等待反编译完成;
2. 在 Jadx 的搜索框(快捷键 Ctrl+Shift+F)输入关键词 `Aegon`,会看到大量以 `com.kuaishou.aegon` 为包名的类;
3. 优先查看 `Aegon` 主类(即 `com.kuaishou.aegon.Aegon`),这是网络库的入口类。
4. 在 Aegon 类中找 QUIC 相关方法。打开 包含 `quic` 关键词的方法 / 字段;,包含 `config`(配置)、`update`(更新)的方法(因为 QUIC 的开启 / 关闭是通过配置更新实现的)。
很快能看到 `nativeUpdateConfig` 这个方法 —— 名字里的 `native` 说明是 Native 层方法,`UpdateConfig` 说明是更新网络配置,这正是修改 QUIC 开关的核心入口;
查看该方法的参数:通常是一个 String 类型的 JSON 字符串,点进方法引用(右键→Find Usages),能看到调用处传入的 JSON 里包含 `enable_quic` 字段(值为 true/false),坐实这是控制 QUIC 的关键方法。
用 Frida Hook 该方法,然后结合Postern抓包。
Hook 禁用 QUIC 后,为什么还需要结合 Postern 抓包?
核心原因是:Hook 只解决了 QUIC 协议降级的问题,但手机 App 的流量默认不会主动转发到电脑的抓包工具(如 Charles/mitmproxy),Postern 的核心作用是做「系统级流量转发」,让降级后的 HTTP/HTTPS 流量能被抓包工具捕获。
## hook代码
frida 16.0.19
frida-tools 12.1.2
夜神 安卓7(32位)
快手APP 9.2
Postern 3.1.2
```javascript
import frida, sys
jscode = """
Java.perform(
function () {
var Aegon = Java.use('com.kuaishou.aegon.Aegon');
Aegon.nativeUpdateConfig.implementation = function (a,b) {
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":[]}';
return this.nativeUpdateConfig(a,b);
}
}
);
"""
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
process = frida.get_remote_device()
#pid = process.spawn(['com.kuaishou.nebula']) # 极速
pid = process.spawn(['com.smile.gifmaker']) # app
session = process.attach(pid)
script = session.create_script(jscode)
script.on('message',on_message)
script.load()
process.resume(pid)
```
## Postern
配置代理,代理类型用**socks**

配置规则

---
## 示例

================================================
FILE: 第八章:抓包技巧汇总/抖音app抓包.md
================================================
# 抖音app抓包
核心逻辑:Hook 抖音网络库 libsscronet.so,修改 QUIC 配置使其降级为 HTTPS。
```javascript
Java.perform(function() {
const CronetEngine = Java.use("org.chromium.net.CronetEngine");
// Hook配置构建器,禁用QUIC
CronetEngine.Builder.prototype.enableQuic.implementation = function(enable) {
console.log("禁用QUIC: enableQuic(false)");
return this.enableQuic(false);
};
// 备选:Hook native层更新配置
const Aegon = Java.use("com.bytedance.aegon.Aegon");
if (Aegon) {
Aegon.nativeUpdateConfig.implementation = function(configStr) {
const newConfig = configStr.replace(/"enable_quic":true/, '"enable_quic":false');
console.log("修改QUIC配置:", newConfig);
return this.nativeUpdateConfig(newConfig);
};
}
});
```
================================================
FILE: 第八章:抓包技巧汇总/某物app抓包.md
================================================
## 环境准备
模拟器夜神安卓7版本。配合charles的抓包步骤:[http://t.csdn.cn/lpNaV](http://t.csdn.cn/lpNaV)
模拟器需要是64位的,在商店下载推荐版本时会提示更新。

安装后,创建64位的模拟器,从商店下载app

打开后再按要求更新一下,即可成功进入APP。

更新后的版本:4.95.1.10
---
## No_PROXY抓包
发现搜索后没抓到有用的数据包,但是有其他包,可能这个APP采用了 NO_PROXY 的方式拒绝代理。

那我们可以采用VPN转发的方式进行测试,如果还不行就需要分析源码进行Hook 或者更换其他类型的抓包工具。
我用 drony 转发并没有成功,所以来分析源码。

com.shizhuang.duapp.common.net.DuHttpConfig.a

在本地进行hook:
```python
import frida, sys
def on_message(message, data):
print("[%s] => %s" % (message, data))
# dewu 4.95.1.10
session = frida.get_remote_device().attach('com.shizhuang.duapp')
# okhttp3拦截器
js_code2 = """
Java.perform(function(){
console.log("1 start hook");
var ba = Java.use('okhttp3.internal.http.RealInterceptorChain');
if (ba){
console.log("2 find class");
ba.proceed.overload('okhttp3.Request').implementation = function(a1){
console.log("3 find method");
console.log(a1);
return ba.proceed(a1)
}
}
})
"""
js_code1 = """
Java.perform(function(){
console.log("1 start hook");
var ba = Java.use('com.shizhuang.duapp.common.helper.net.interceptor.HttpRequestInterceptor').$new();
if (ba){
console.log("2 find class");
ba.intercept.implementation = function(a1){
console.log("3 find method");
console.log(a1);
return ba.intercept(a1)
}
}
})
"""
script = session.create_script(js_code1)
script.on('message', on_message)
script.load()
sys.stdin.read()
```
找到 com.shizhuang.duapp.modules.mall_search.api.ProductService.searchProductNew()

================================================
FILE: 第八章:抓包技巧汇总/点评app抓包案例.md
================================================
本文是大众点评APP的分析记录。
> 声明:文章内容仅供参考学习,如有侵权请联系作者进行删除。
案例环境:夜神安卓5,APP版本10.45.7。
工具:Frida、Charles。

点评看不到http/https数据包,它走了自己的CIP协议,网上的抓包方案有降级或者VPN转发。
本文通过hook的方式来抓http/https数据包。
用super-Jadx时内存溢出,我删除了一些无用文件,将dex分批反编译,这块就不再说了。
---
@[toc]
---
## Hook 抓包
Hook代码:

执行hook脚本后,成功抓到包。

---
## Hook http/https请求信息
Hook代码:

查看执行结果:

---
## Hook 明文响应内容
Hook代码:

查看执行结果:

格式化后和设备页面信息对比,发现内容一致。

---
## Hook 代码整理
```python
import frida, sys
def on_message(message, data):
print("[%s] => %s" % (message, data))
session = frida.get_usb_device().attach('com.dianping.v1')
js_code = """
Java.perform(function(){
Java.openClassFile("/data/local/tmp/r0gson.dex").load();
const gson = Java.use('com.r0ysue.gson.Gson');
var c1 = Java.use("com.dianping.nvnetwork.tunnel2.a");
c1.isSocketConnected.implementation = function () {
return false;
}
var bb = Java.use("com.dianping.dataservice.mapi.b");
bb.b.overload('java.lang.String', 'com.dianping.dataservice.mapi.c').implementation = function(a1, a2){
//console.log("**************************** http start");
console.log(a1);
// console.log('a2:', a2);
var res = this.b(a1, a2);
// console.log(res);
//console.log("**************************** http end");
return res;
}
var d = Java.use("com.dianping.dataservice.mapi.impl.d")
d.a.overload('java.lang.String', 'java.lang.String').implementation = function(a1, a2){
//console.log("**************************** https start");
var res = this.a(a1, a2);
console.log(res);
//console.log("**************************** https end");
return res;
};
var c3 = Java.use("com.dianping.picassocontroller.jse.c");
c3.a.overload('com.dianping.picassocontroller.vc.e', 'java.lang.String', '[Ljava.lang.Object;').implementation = function (a,b,c) {
console.log('a: ', a);
console.log('b: ', b);
console.log('c: ', c);
var v = this.a(a,b,c)
console.log(v.string())
return v;
}
//// hook decryptData
var ByteString = Java.use("com.android.okhttp.okio.ByteString");
var SocketSecureManager = Java.use("com.dianping.nvnetwork.tunnel.Encrypt.SocketSecureManager");
SocketSecureManager.decryptData.implementation = function(bstr, str){
console.log('bstr: ', bstr);
console.log('bstr-tojson:',gson.$new().toJson(bstr));
console.log('bstr-hex: ', ByteString.of(bstr).hex());
console.log('str: ', str);
var ret = this.decryptData(bstr, str);
// console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
console.log('decryptData Results: ', ByteString.of(ret).hex());
return ret;
}
// var AESUtils = Java.use("com.meituan.android.common.unionid.oneid.util.AESUtils");
// AESUtils.decrypt.implementation = function(str){
// console.log('decrypt is called');
// str = "RNtYlL8BsMe4EOqz-X0a1WAw3FwHsr1fdXSOBRnPEF_MiYYvJ1GSqvIIA1NwwTUxuoNWGGueSBRl50pmkidrgdQmVUUScNhW4FpBl1ZFPSyJAz4Zo0PpDNStJnb5JCf8fEe8oDXOCAsptjpuGpRJGClsKeIqe9ph6gAyvYfOk2XafwXbHf4VlsjATDVI7r4f-2s6QQ5Mfc6jvRMyqNdLJNtLwg5XDEmL4Leu7fCnHJbJ46O8hy8MFuN38avBqh6N-2s6QQ5Mfc6jvRMyqNdLJLVj6r8HF-qtkeIznxOc2qXKVyQ4dzMLEBQjCADd9vGF"
// var ret = this.decrypt(str);
// console.log('decrypt ret value is ' + ret);
// return ret;
// };
})
"""
script = session.create_script(js_code)
script.on('message', on_message)
script.load()
sys.stdin.read()
```
================================================
FILE: 第六章:安卓逆向/Frida/Frida基本方法.md
================================================
## 基本命令
|命令 | 简介 |
|--|--|
|adb devices |列出设备 |
|adb connect 127.0.0.1:62001 |连接设备(注意端口)|
|adb shell |进入shell|
|adb kill-server |关闭服务|
|adb start-server |启动服务|
|adb reboot |重启设备|
|adb forward tcp:27042 tcp:27042 |端口转发|
|adb shell dumpsys activity top |查看apk包名|
|frida-ls-devices |列出所有连接到电脑上的设备|
|frida-ps -U |列出正在运行的进程|
|frida-ps -Uai |列出安装的程序|
|frida-ps -Ua |列出运行中的程序|
|frida-ps -D "设备id" |连接frida到个指定的设备|
|frida-trace -U -f Name -i "函数名"| 跟踪某个函数|
|frida-trace -U -f Name -m "方法名" |跟踪某个方法|
|frida -U -l *.js "进程ID" |加载Js脚本|
|frida-discover -n Name |发现程序内部函数|
|frida-discover -p pid |发现程序内部函数|
|frida-kill -U | "进程ID" |结束进程|
## Hook 一般函数
```javascript
var MyClass = Java.use('xx.xx.MainActivity');
MyClass.myMethod.implementation = function (arg) {
var ret = this.myMethod(arg);
console.log('Done:' + arg);
return ret;
}
```
## Hook 重载函数
```javascript
myClass.myMethod.overload("java.lang.String").implementation = function(param1){
console.log(param1);
}
myClass.myMethod.overload("[B","[B").implementation = function(param1,param2) {
const p1 = Java.use("java.lang.String").$new(param1);
const p2 = Java.use("java.lang.String").$new(param2);
}
myClass.myMethod.overload("android.context.Context", "boolean").implementation = function(param1, param2){
//do something
}
```
## Hook 构造函数
```javascript
const StringBuilder = Java.use('java.lang.StringBuilder');
StringBuilder.$init.overload('java.lang.String').implementation = function (arg) {
var partial = "";
var result = this.$init(arg);
if (arg !== null) {
partial = arg.toString().slice(0,10);
}
console.log('new StringBuilder("' + partial + '");');
return result;
};
StringBuilder.$init.overload('[B', 'int').implementation = function (arg1,arg2,) {
//do something
}
```
## Hook 成员方法
```javascript
Java.perform(
function(){
var ba = Java.use("com.xx.xx.xx").$new();
if (ba != undefined) {
ba.mdthod.implementation = function (a1) {
//do something
}
}
}
)
```
## Hook 内部类
```javascript
var inInnerClass = Java.use('ese.xposedtest.MainActivity$inInnerClass');
// 类路径$内部类名
inInnerClass.methodInclass.implementation = function(arguments){
var arg0 = arguments[0];
var arg1 = arguments[1];
send("params1: "+ arg0 +" params2: " + arg1);
return this.formInclass(1,"Frida");
}
```
## Hook native函数
```javascript
function hookNativeFun(callback, funName, moduleName) {
var time = 1000;
var address = Module.findExportByName(moduleName, funName);
if (address == null) {
setTimeout(hookNativeFun, time, callback, funName, moduleName);
}
else {
console.log(funName + "hook result")
var nativePointer = new NativePointer(address);
Interceptor.attach(nativePointer, callback);
}
}
```
## 从内存中主动调用Java方法
```javascript
Java.perform(
function(){
Java.choose("com.xx.xx.xx", {
onMatch: function (x) {
ba.signInternal.implementation = function(a1,a2) {
result= x.method(a1,a2);
},
onComplete: function () {
}
})
}
)
```
## 获取所有已加载的类名
```javascript
Java.perform(function(){
Java.enumerateLoadedClasses({
onMatch: function(className) {
send(className);},
onComplete:function(){
send("done");
}
});
});
```
## 获取方法名
```javascript
function getMethodName() {
var ret;
Java.perform(function() {
var Thread = Java.use("java.lang.Thread")
ret = Thread.currentThread().getStackTrace()[2].getMethodName();
});
return ret;
}
```
## 打印堆栈信息
```javascript
function showStacks() {
Java.perform(function() {
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
});
}
```
## 打印类所有方法名
```javascript
function enumMethods(targetClass) {
var ret;
Java.perform(function() {
var hook = Java.use(targetClass);
var ret = hook.class.getDeclaredMethods();
ret.forEach(function(s) {
console.log(s);
})
})
return ret;
}
```
## 构造 context
```js
var current_application = Java.use('android.app.ActivityThread').currentApplication();
var context = current_application.getApplicationContext();
```
## Hook NO_Proxy
```js
Java.perform(function(){
console.log("1 start hook");
try {
var URL = Java.use('java.net.URL')
URL.openConnection.overload('java.net.Proxy').implementation = function (arg1){
return this.openConnection()
}
} catch (e) {
console.log('' + e)
}
try {
var Builder = Java.use('okhttp3.OkHttpClient$Builder')
var mybuilder = Builder.$new()
Builder.proxy.overload('java.net.Proxy').implementation = function (arg1) {
return mybuilder
}
} catch (e) {
console.log('' + e)
}
```
## Hook HashMap-put
```javascript
var hashMap = Java.use("java.util.HashMap");
hashMap.put.implementation = function (a, b) {
// 不行可换 a.equals("username")
if (a=="username") {
console.log("hashMap.put: ", a, b);
printStacks();
}
return this.put(a, b);
}
```
## Hook ArrayList-add
```javascript
var arrayList = Java.use("java.util.ArrayList");
arrayList.add.overload('java.lang.Object').implementation = function (a) {
if (a == "username") {
console.log("arrayList.add: ", a);
showStacks(); // 打印堆栈信息
}
//console.log("arrayList.add: ", a);
return this.add(a);
}
arrayList.add.overload('int', 'java.lang.Object').implementation = function (a, b) {
console.log("arrayList.add: ", a, b);
return this.add(a, b);
}
```
## Hook TextUtils-isEmpty
```javascript
// 判断输入框是否为空
var textUtils = Java.use("android.text.TextUtils");
textUtils.isEmpty.implementation = function (a) {
if (a == "TURJNk1EQTZNREE2TURBNk1EQTZNREE9") {
console.log("textUtils.isEmpty: ", a);
printStacks();
}
//console.log("textUtils.isEmpty: ", a);
return this.isEmpty(a);
}
```
## hook Base64-encodeToString
```javascript
var base64 = Java.use("android.util.Base64");
base64.encodeToString.overload('[B', 'int').implementation = function (a, b) {
console.log("base64.encodeToString: ", JSON.stringify(a));
var result = this.encodeToString(a, b);
console.log("base64.encodeToString result: ", result)
printStacks();
return result;
}
```
## okhttp3 rpc
```javascript
rpc.exports = {
request_url: function (url) {
return new Promise(function(resolve, reject) {
Java.perform(function () {
var OkHttpClient=Java.use("okhttp3.OkHttpClient");
var Builder=Java.use("okhttp3.Request$Builder");
var client = OkHttpClient.$new()
var request = Builder.$new().get().url(url).build()
var response = client.newCall(request).execute()
resolve(response.body().string())
});
});
}
};
```
## okhttp3 GET
```javascript
function okhttp3_get(url, headers_str){
let body = null;
Java.perform(() => {
const BuilderClazz = Java.use('okhttp3.Request$Builder');
const OkHttpClientClazz = Java.use('okhttp3.OkHttpClient');
try{
let builder = BuilderClazz.$new();
builder = builder.url(url);
if(headers_str != null && headers_str != ''){
let headers = JSON.parse(headers_str);
for(let key in headers){
builder = builder.addHeader(key, headers[key]);
}
}
let request = builder.build();
if(!okhttp3_client){
okhttp3_client = OkHttpClientClazz.$new();
}
let call = okhttp3_client.newCall(request);
let response = call.execute();
body = response.body().string();
}catch(e){
console.error(e);
}
});
return body;
}
```
## okhttp3 POST
```javascript
function okhttp3_post(url, headers_str, media_type, body){
let ret = null;
Java.perform(() => {
const BuilderClazz = Java.use('okhttp3.Request$Builder');
const OkHttpClientClazz = Java.use('okhttp3.OkHttpClient');
const MediaTypeClazz = Java.use('okhttp3.MediaType');
const RequestBodyClazz = Java.use('okhttp3.RequestBody');
try{
let builder = BuilderClazz.$new();
builder = builder.url(url);
if(headers_str != null && headers_str != ''){
let headers = JSON.parse(headers_str);
for(let key in headers){
builder = builder.addHeader(key, headers[key]);
}
}
let m_type = MediaTypeClazz.parse(media_type);
let request_body = RequestBodyClazz.create(m_type, body);
builder = builder.post(request_body);
let request = builder.build();
if(!okhttp3_client){
okhttp3_client = OkHttpClientClazz.$new();
}
let call = okhttp3_client.newCall(request);
let response = call.execute();
ret = response.body().string();
}catch(e){
console.error(e);
}
});
return ret;
}
```
================================================
FILE: 第六章:安卓逆向/Frida/Frida自吐算法.js
================================================
// 代码引用自 Mobile security 王铁头
var N_ENCRYPT_MODE = 1
var N_DECRYPT_MODE = 2
function showStacks() {
var Exception = Java.use("java.lang.Exception");
var ins = Exception.$new("Exception");
var straces = ins.getStackTrace();
if (undefined == straces || null == straces) {
return;
}
console.log("============================= Stack strat=======================");
console.log("");
for (var i = 0; i < straces.length; i++) {
var str = " " + straces[i].toString();
console.log(str);
}
console.log("");
console.log("============================= Stack end=======================\r\n");
Exception.$dispose();
}
//工具相关函数
var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
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));
function stringToBase64(e) {
var r, a, c, h, o, t;
for (c = e.length, a = 0, r = ''; a < c;) {
if (h = 255 & e.charCodeAt(a++), a == c) {
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4),
r += '==';
break
}
if (o = e.charCodeAt(a++), a == c) {
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
r += base64EncodeChars.charAt((15 & o) << 2),
r += '=';
break
}
t = e.charCodeAt(a++),
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),
r += base64EncodeChars.charAt(63 & t)
}
return r
}
function base64ToString(e) {
var r, a, c, h, o, t, d;
for (t = e.length, o = 0, d = ''; o < t;) {
do
r = base64DecodeChars[255 & e.charCodeAt(o++)];
while (o < t && r == -1);
if (r == -1)
break;
do
a = base64DecodeChars[255 & e.charCodeAt(o++)];
while (o < t && a == -1);
if (a == -1)
break;
d += String.fromCharCode(r << 2 | (48 & a) >> 4);
do {
if (c = 255 & e.charCodeAt(o++), 61 == c)
return d;
c = base64DecodeChars[c]
} while (o < t && c == -1);
if (c == -1)
break;
d += String.fromCharCode((15 & a) << 4 | (60 & c) >> 2);
do {
if (h = 255 & e.charCodeAt(o++), 61 == h)
return d;
h = base64DecodeChars[h]
} while (o < t && h == -1);
if (h == -1)
break;
d += String.fromCharCode((3 & c) << 6 | h)
}
return d
}
function hexToBase64(str) {
return base64Encode(String.fromCharCode.apply(null, str.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ")));
}
function base64ToHex(str) {
for (var i = 0, bin = base64Decode(str.replace(/[ \r\n]+$/, "")), hex = []; i < bin.length; ++i) {
var tmp = bin.charCodeAt(i).toString(16);
if (tmp.length === 1)
tmp = "0" + tmp;
hex[hex.length] = tmp;
}
return hex.join("");
}
function hexToBytes(str) {
var pos = 0;
var len = str.length;
if (len % 2 != 0) {
return null;
}
len /= 2;
var hexA = new Array();
for (var i = 0; i < len; i++) {
var s = str.substr(pos, 2);
var v = parseInt(s, 16);
hexA.push(v);
pos += 2;
}
return hexA;
}
function bytesToHex(arr) {
var str = '';
var k, j;
for (var i = 0; i < arr.length; i++) {
k = arr[i];
j = k;
if (k < 0) {
j = k + 256;
}
if (j < 16) {
str += "0";
}
str += j.toString(16);
}
return str;
}
function stringToHex(str) {
var val = "";
for (var i = 0; i < str.length; i++) {
if (val == "")
val = str.charCodeAt(i).toString(16);
else
val += str.charCodeAt(i).toString(16);
}
return val
}
function stringToBytes(str) {
var ch, st, re = [];
for (var i = 0; i < str.length; i++) {
ch = str.charCodeAt(i);
st = [];
do {
st.push(ch & 0xFF);
ch = ch >> 8;
}
while (ch);
re = re.concat(st.reverse());
}
return re;
}
//将byte[]转成String的方法
function bytesToString(arr) {
var str = '';
arr = new Uint8Array(arr);
for (var i in arr) {
str += String.fromCharCode(arr[i]);
}
return str;
}
function bytesToBase64(e) {
var r, a, c, h, o, t;
for (c = e.length, a = 0, r = ''; a < c;) {
if (h = 255 & e[a++], a == c) {
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4),
r += '==';
break
}
if (o = e[a++], a == c) {
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
r += base64EncodeChars.charAt((15 & o) << 2),
r += '=';
break
}
t = e[a++],
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),
r += base64EncodeChars.charAt(63 & t)
}
return r
}
function base64ToBytes(e) {
var r, a, c, h, o, t, d;
for (t = e.length, o = 0, d = []; o < t;) {
do
r = base64DecodeChars[255 & e.charCodeAt(o++)];
while (o < t && r == -1);
if (r == -1)
break;
do
a = base64DecodeChars[255 & e.charCodeAt(o++)];
while (o < t && a == -1);
if (a == -1)
break;
d.push(r << 2 | (48 & a) >> 4);
do {
if (c = 255 & e.charCodeAt(o++), 61 == c)
return d;
c = base64DecodeChars[c]
} while (o < t && c == -1);
if (c == -1)
break;
d.push((15 & a) << 4 | (60 & c) >> 2);
do {
if (h = 255 & e.charCodeAt(o++), 61 == h)
return d;
h = base64DecodeChars[h]
} while (o < t && h == -1);
if (h == -1)
break;
d.push((3 & c) << 6 | h)
}
return d
}
//stringToBase64 stringToHex stringToBytes
//base64ToString base64ToHex base64ToBytes
// hexToBase64 hexToBytes
// bytesToBase64 bytesToHex bytesToString
Java.perform(function () {
var secretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');
secretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function (a, b) {
showStacks();
var result = this.$init(a, b);
console.log("======================================");
console.log("算法名:" + b + "|str密钥:" + bytesToString(a));
console.log("算法名:" + b + "|Hex密钥:" + bytesToHex(a));
return result;
}
var DESKeySpec = Java.use('javax.crypto.spec.DESKeySpec');
DESKeySpec.$init.overload('[B').implementation = function (a) {
showStacks();
var result = this.$init(a);
console.log("======================================");
var bytes_key_des = this.getKey();
console.log("des密钥 |str " + bytesToString(bytes_key_des));
console.log("des密钥 |hex " + bytesToHex(bytes_key_des));
return result;
}
DESKeySpec.$init.overload('[B', 'int').implementation = function (a, b) {
showStacks();
var result = this.$init(a, b);
console.log("======================================");
var bytes_key_des = this.getKey();
console.log("des密钥 |str " + bytesToString(bytes_key_des));
console.log("des密钥 |hex " + bytesToHex(bytes_key_des));
return result;
}
var mac = Java.use('javax.crypto.Mac');
mac.getInstance.overload('java.lang.String').implementation = function (a) {
showStacks();
var result = this.getInstance(a);
console.log("======================================");
console.log("算法名:" + a);
return result;
}
mac.update.overload('[B').implementation = function (a) {
//showStacks();
this.update(a);
console.log("======================================");
console.log("update:" + bytesToString(a))
}
mac.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
//showStacks();
this.update(a, b, c)
console.log("======================================");
console.log("update:" + bytesToString(a) + "|" + b + "|" + c);
}
mac.doFinal.overload().implementation = function () {
//showStacks();
var result = this.doFinal();
console.log("======================================");
console.log("doFinal结果: |str :" + bytesToString(result));
console.log("doFinal结果: |hex :" + bytesToHex(result));
console.log("doFinal结果: |base64 :" + bytesToBase64(result));
return result;
}
mac.doFinal.overload('[B').implementation = function (a) {
//showStacks();
var result = this.doFinal(a);
console.log("======================================");
console.log("doFinal参数: |str :" + bytesToString(a));
console.log("doFinal参数: |hex :" + bytesToHex(a));
console.log("doFinal结果: |str :" + bytesToString(result));
console.log("doFinal结果: |hex :" + bytesToHex(result));
console.log("doFinal结果: |base64 :" + bytesToBase64(result));
return result;
}
var md = Java.use('java.security.MessageDigest');
md.getInstance.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {
//showStacks();
console.log("======================================");
console.log("算法名:" + a);
return this.getInstance(a, b);
}
md.getInstance.overload('java.lang.String').implementation = function (a) {
//showStacks();
console.log("======================================");
console.log("算法名:" + a);
return this.getInstance(a);
}
md.update.overload('[B').implementation = function (a) {
//showStacks();
console.log("======================================");
console.log("update:" + bytesToString(a))
return this.update(a);
}
md.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
//showStacks();
console.log("======================================");
console.log("update:" + bytesToString(a) + "|" + b + "|" + c);
return this.update(a, b, c);
}
md.digest.overload().implementation = function () {
//showStacks();
console.log("======================================");
var result = this.digest();
console.log("digest结果 |hex:" + bytesToHex(result));
console.log("digest结果 |base64:" + bytesToBase64(result));
return result;
}
md.digest.overload('[B').implementation = function (a) {
//showStacks();
console.log("======================================");
console.log("digest参数 |str:" + bytesToString(a));
console.log("digest参数 |hex:" + bytesToHex(a));
var result = this.digest(a);
console.log("digest结果: |hex" + bytesToHex(result));
console.log("digest结果: |base64" + bytesToBase64(result));
return result;
}
var ivParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');
ivParameterSpec.$init.overload('[B').implementation = function (a) {
//showStacks();
var result = this.$init(a);
console.log("======================================");
console.log("iv向量: |str:" + bytesToString(a));
console.log("iv向量: |hex:" + bytesToHex(a));
return result;
}
var cipher = Java.use('javax.crypto.Cipher');
cipher.getInstance.overload('java.lang.String').implementation = function (a) {
//showStacks();
var result = this.getInstance(a);
console.log("======================================");
console.log("模式填充:" + a);
return result;
}
cipher.init.overload('int', 'java.security.Key').implementation = function (a, b) {
//showStacks();
var result = this.init(a, b);
console.log("======================================");
if (N_ENCRYPT_MODE == a)
{
console.log("init | 加密模式");
}
else if(N_DECRYPT_MODE == a)
{
console.log("init | 解密模式");
}
var bytes_key = b.getEncoded();
console.log("init key:" + "|str密钥:" + bytesToString(bytes_key));
console.log("init key:" + "|Hex密钥:" + bytesToHex(bytes_key));
return result;
}
cipher.init.overload('int', 'java.security.cert.Certificate').implementation = function (a, b) {
//showStacks();
var result = this.init(a, b);
console.log("======================================");
if (N_ENCRYPT_MODE == a)
{
console.log("init | 加密模式");
}
else if(N_DECRYPT_MODE == a)
{
console.log("init | 解密模式");
}
return result;
}
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (a, b, c) {
//showStacks();
var result = this.init(a, b, c);
console.log("======================================");
if (N_ENCRYPT_MODE == a)
{
console.log("init | 加密模式");
}
else if(N_DECRYPT_MODE == a)
{
console.log("init | 解密模式");
}
var bytes_key = b.getEncoded();
console.log("init key:" + "|str密钥:" + bytesToString(bytes_key));
console.log("init key:" + "|Hex密钥:" + bytesToHex(bytes_key));
return result;
}
cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function (a, b, c) {
//showStacks();
var result = this.init(a, b, c);
if (N_ENCRYPT_MODE == a)
{
console.log("init | 加密模式");
}
else if(N_DECRYPT_MODE == a)
{
console.log("init | 解密模式");
}
return result;
}
cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function (a, b, c) {
//showStacks();
var result = this.init(a, b, c);
if (N_ENCRYPT_MODE == a)
{
console.log("init | 加密模式");
}
else if(N_DECRYPT_MODE == a)
{
console.log("init | 解密模式");
}
var bytes_key = b.getEncoded();
console.log("init key:" + "|str密钥:" + bytesToString(bytes_key));
console.log("init key:" + "|Hex密钥:" + bytesToHex(bytes_key));
return result;
}
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters').implementation = function (a, b, c) {
//showStacks();
var result = this.init(a, b, c);
if (N_ENCRYPT_MODE == a)
{
console.log("init | 加密模式");
}
else if(N_DECRYPT_MODE == a)
{
console.log("init | 解密模式");
}
var bytes_key = b.getEncoded();
console.log("init key:" + "|str密钥:" + bytesToString(bytes_key));
console.log("init key:" + "|Hex密钥:" + bytesToHex(bytes_key));
return result;
}
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom').implementation = function (a, b, c, d) {
//showStacks();
var result = this.init(a, b, c, d);
if (N_ENCRYPT_MODE == a)
{
console.log("init | 加密模式");
}
else if(N_DECRYPT_MODE == a)
{
console.log("init | 解密模式");
}
var bytes_key = b.getEncoded();
console.log("init key:" + "|str密钥:" + bytesToString(bytes_key));
console.log("init key:" + "|Hex密钥:" + bytesToHex(bytes_key));
return result;
}
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom').implementation = function (a, b, c, d) {
//showStacks();
var result = this.init(a, b, c, d);
if (N_ENCRYPT_MODE == a)
{
console.log("init | 加密模式");
}
else if(N_DECRYPT_MODE == a)
{
console.log("init | 解密模式");
}
var bytes_key = b.getEncoded();
console.log("init key:" + "|str密钥:" + bytesToString(bytes_key));
console.log("init key:" + "|Hex密钥:" + bytesToHex(bytes_key));
return result;
}
cipher.update.overload('[B').implementation = function (a) {
//showStacks();
var result = this.update(a);
console.log("======================================");
console.log("update:" + bytesToString(a));
return result;
}
cipher.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
//showStacks();
var result = this.update(a, b, c);
console.log("======================================");
console.log("update:" + bytesToString(a) + "|" + b + "|" + c);
return result;
}
cipher.doFinal.overload().implementation = function () {
//showStacks();
var result = this.doFinal();
console.log("======================================");
console.log("doFinal结果: |str :" + bytesToString(result));
console.log("doFinal结果: |hex :" + bytesToHex(result));
console.log("doFinal结果: |base64 :" + bytesToBase64(result));
return result;
}
cipher.doFinal.overload('[B').implementation = function (a) {
//showStacks();
var result = this.doFinal(a);
console.log("======================================");
console.log("doFinal参数: |str :" + bytesToString(a));
console.log("doFinal参数: |hex :" + bytesToHex(a));
console.log("doFinal结果: |str :" + bytesToString(result));
console.log("doFinal结果: |hex :" + bytesToHex(result));
console.log("doFinal结果: |base64 :" + bytesToBase64(result));
return result;
}
var x509EncodedKeySpec = Java.use('java.security.spec.X509EncodedKeySpec');
x509EncodedKeySpec.$init.overload('[B').implementation = function (a) {
//showStacks();
var result = this.$init(a);
console.log("======================================");
console.log("RSA密钥:" + bytesToBase64(a));
return result;
}
var rSAPublicKeySpec = Java.use('java.security.spec.RSAPublicKeySpec');
rSAPublicKeySpec.$init.overload('java.math.BigInteger', 'java.math.BigInteger').implementation = function (a, b) {
//showStacks();
var result = this.$init(a, b);
console.log("======================================");
//console.log("RSA密钥:" + bytesToBase64(a));
console.log("RSA密钥N:" + a.toString(16));
console.log("RSA密钥E:" + b.toString(16));
return result;
}
var KeyPairGenerator = Java.use('java.security.KeyPairGenerator');
KeyPairGenerator.generateKeyPair.implementation = function ()
{
//showStacks();
var result = this.generateKeyPair();
console.log("======================================");
var str_private = result.getPrivate().getEncoded();
var str_public = result.getPublic().getEncoded();
console.log("公钥 |hex" + bytesToHex(str_public));
console.log("私钥 |hex" + bytesToHex(str_private));
return result;
}
KeyPairGenerator.genKeyPair.implementation = function ()
{
//showStacks();
var result = this.genKeyPair();
console.log("======================================");
var str_private = result.getPrivate().getEncoded();
var str_public = result.getPublic().getEncoded();
console.log("公钥 |hex" + bytesToHex(str_public));
console.log("私钥 |hex" + bytesToHex(str_private));
return result;
}
});
================================================
FILE: 第六章:安卓逆向/Frida/Frida自吐算法.py
================================================
# -*- coding: UTF-8 -*-
# 代码引用自 guyezhou51
import frida
import sys
def on_message(message, data):
if message['type'] == 'send':
ss = "[*]{0}".format(message['payload'])
file_handle = open('log.txt', mode='a+')
file_handle.write('%s \r\n' % (ss))
file_handle.close()
else:
print(message)
def get_js():
htmlstr = '''
var N_ENCRYPT_MODE = 1;
var N_DECRYPT_MODE = 2;
function showStacks() {
var Exception = Java.use("java.lang.Exception");
var ins = Exception.$new("Exception");
var straces = ins.getStackTrace();
if (undefined == straces || null == straces) {
return;
}
mylog("===================== Stack strat=======================","","",0);
for (var i = 0; i < straces.length; i++) {
var str = " " + straces[i].toString();
mylog(str,"","",0);
}
mylog("====================== Stack end=======================","","",0);
Exception.$dispose();
};
//工具相关函数
var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
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));
function bytesToHex(arr) {
var str = '';
arr = new Uint8Array(arr);
var k, j;
for (var i = 0; i < arr.length; i++) {
k = arr[i];
j = k;
if (k < 0) {
j = k + 256;
}
if (j < 16) {
str += "0";
}
str += j.toString(16);
}
return str;
};
//将byte[]转成String的方法
function bytesToString(arr) {
var str = '';
arr = new Uint8Array(arr);
for (var i in arr) {
str += String.fromCharCode(arr[i]);
}
return str;
};
function bytesToBase64(e) {
e = new Uint8Array(e);
var r, a, c, h, o, t;
for (c = e.length, a = 0, r = ''; a < c;) {
if (h = 255 & e[a++], a == c) {
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4),
r += '==';
break;
}
if (o = e[a++], a == c) {
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
r += base64EncodeChars.charAt((15 & o) << 2),
r += '=';
break;
}
t = e[a++],
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),
r += base64EncodeChars.charAt(63 & t);
}
return r;
};
//stringToBase64 stringToHex stringToBytes
//base64ToString base64ToHex base64ToBytes
// hexToBase64 hexToBytes
// bytesToBase64 bytesToHex bytesToString
function mylog(s,code,s2,ii){
if(ii==1){
//输出hex类型
var str = bytesToHex(code)+s2;
console.log(s+" |HEX :"+str);
send(s+" |HEX :"+str);
//输出base64
str = bytesToBase64(code)+s2;
console.log( s+" |BASE64 :"+str);
send(s+" |BASE64 :"+str);
//输出string类型
str = bytesToString(code)+s2;
console.log(s+" |str :"+str);
send(s+" |str :"+str);
}else{
console.log("print: "+s);
send("print: "+s);
}
};
Java.perform(function () {
var secretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');
var AE算法名称 = null;
secretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function (a, b) {
showStacks();
var result = this.$init(a, b);
mylog("======================================","","",0);
mylog("算法名:" + b + "| 密钥" , a,"",1);
AE算法名称=b;
return result;
};
secretKeySpec.$init.overload('[B', 'int','int','java.lang.String').implementation = function (a,i1,i2, b) {
showStacks();
var result = this.$init(a,i1,i2,b);
mylog("======================================","","",0);
mylog("算法名:" + b + "| 密钥" , a," |开始取的位置"+i1+"取长度:"+i2,1);
AE算法名称=b;
return result;
};
var DESKeySpec = Java.use('javax.crypto.spec.DESKeySpec');
DESKeySpec.$init.overload('[B').implementation = function (a) {
showStacks();
var result = this.$init(a);
mylog("======================================","","",0);
var bytes_key_des = this.getKey();
mylog("des密钥 " ,bytes_key_des,"",1);
return result;
};
DESKeySpec.$init.overload('[B', 'int').implementation = function (a, b) {
showStacks();
var result = this.$init(a, b);
mylog("======================================","","",0);
var bytes_key_des = this.getKey();
mylog("des密钥 " , bytes_key_des,"",1);
return result;
};
//3des
var DESedeKeySpec = Java.use('javax.crypto.spec.DESedeKeySpec');
DESedeKeySpec.$init.overload('[B').implementation = function (a) {
showStacks();
var result = this.$init(a);
mylog("======================================","","",0);
var bytes_key_des = this.getKey();
mylog("des密钥 " ,bytes_key_des,"",1);
return result;
};
DESedeKeySpec.$init.overload('[B', 'int').implementation = function (a, b) {
showStacks();
var result = this.$init(a, b);
mylog("======================================","","",0);
var bytes_key_des = this.getKey();
mylog("des密钥 " , bytes_key_des,"",1);
return result;
};
var mac = Java.use('javax.crypto.Mac');
var MAC算法名称=null;
mac.getInstance.overload('java.lang.String').implementation = function (a) {
showStacks();
var result = this.getInstance(a);
mylog("======================================","","",0);
mylog("Mac算法名:" + a,"","",0);
MAC算法名称 =a;
return result;
};
mac.update.overload('[B').implementation = function (a) {
showStacks();
this.update(a);
mylog("======================================","","",0);
mylog(MAC算法名称+"update:" ,a,"",1);
};
mac.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
showStacks();
this.update(a, b, c);
mylog("======================================","","",0);
mylog(MAC算法名称+"update:" , a , "|" + b + "|" + c,1);
};
mac.update.overload('java.nio.ByteBuffer').implementation = function (a) {
showStacks();
this.update(a);
mylog("======================================","","",0);
mylog(MAC算法名称+"update:" ,a.array() , "",1);
};
mac.doFinal.overload().implementation = function () {
showStacks();
var result = this.doFinal();
mylog("======================================","","",0);
mylog(MAC算法名称+"doFinal结果:", result,"",1);
return result;
};
mac.doFinal.overload('[B').implementation = function (a) {
showStacks();
var result = this.doFinal(a);
mylog("======================================","","",0);
mylog(MAC算法名称+"doFinal参数:",a,"",1);
return result;
};
mac.doFinal.overload('[B','int').implementation = function (a,b) {
showStacks();
var result = this.doFinal(a,b);
mylog("======================================","","",0);
mylog(MAC算法名称+"doFinal参数:",a," | "+b,1);
return result;
};
var md = Java.use('java.security.MessageDigest');
var HX算法名称=null;
md.getInstance.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {
showStacks();
mylog("======================================","","",0);
mylog("算法名:" + a,"","",0);
HX算法名称 = a;
return this.getInstance(a, b);
};
md.getInstance.overload('java.lang.String', 'java.security.Provider').implementation = function (a, b) {
showStacks();
mylog("======================================","","",0);
mylog("算法名:" + a,"","",0);
HX算法名称 = a;
return this.getInstance(a, b);
};
md.getInstance.overload('java.lang.String').implementation = function (a) {
showStacks();
mylog("======================================","","",0);
mylog("算法名:" + a,"","",0);
HX算法名称 = a;
return this.getInstance(a);
};
md.update.overload('[B').implementation = function (a) {
showStacks();
mylog("======================================","","",0);
mylog(HX算法名称+"_update:" , a,"",1);
return this.update(a);
};
md.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
showStacks();
mylog("======================================","","",0);
mylog(HX算法名称+"_update:" , a , "|" + b + "|" + c,1);
return this.update(a, b, c);
};
md.update.overload('java.nio.ByteBuffer').implementation = function (a) {
showStacks();
this.update(a);
mylog("======================================","","",0);
mylog(HX算法名称+"update:" ,a.array() , "",1);
};
md.digest.overload().implementation = function () {
showStacks();
mylog("======================================","","",0);
var result = this.digest();
mylog(HX算法名称+"_digest结果:" , result,"",1);
return result;
};
md.digest.overload('[B').implementation = function (a) {
showStacks();
mylog("======================================","","",0);
mylog(HX算法名称+"_digest参数:" , a,"",1);
var result = this.digest(a);
mylog(HX算法名称+"_digest结果:" , result,"",1);
return result;
} ;
md.digest.overload('[B','int','int').implementation = function (a,b,c) {
showStacks();
mylog("======================================","","",0);
mylog(HX算法名称+"_digest参数:" , a," |"+b+"|"+c,1);
var result = this.digest(a,b,c);
mylog(HX算法名称+"_digest结果:" , result,"",1);
return result;
};
var ivParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');
ivParameterSpec.$init.overload('[B').implementation = function (a) {
showStacks();
var result = this.$init(a);
mylog("======================================","","",0);
mylog("iv向量: " ,a,"",1);
return result;
};
var ivParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');
ivParameterSpec.$init.overload('[B','int','int').implementation = function (a,b,c) {
showStacks();
var result = this.$init(a,b,c);
mylog("======================================","","",0);
mylog("iv向量: " ,a," |"+b+"|"+c,1);
return result;
};
var cipher = Java.use('javax.crypto.Cipher');
cipher.getInstance.overload('java.lang.String').implementation = function (a) {
showStacks();
var result = this.getInstance(a);
mylog("======================================","","",0);
mylog(AE算法名称+"_模式填充:" + a,"","",0);
return result;
};
cipher.init.overload('int', 'java.security.Key').implementation = function (a, b) {
showStacks();
var result = this.init(a, b);
mylog("======================================","","",0);
if (N_ENCRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 加密模式","","",0);
}
else if(N_DECRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 解密模式","","",0);
};
var bytes_key = b.getEncoded();
mylog(AE算法名称+"_init key:" + "|密钥" , bytes_key,"",1);
return result;
};
cipher.init.overload('int', 'java.security.cert.Certificate').implementation = function (a, b) {
showStacks();
var result = this.init(a, b);
mylog("======================================","","",0);
if (N_ENCRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 加密模式","","",0);
}
else if(N_DECRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 解密模式","","",0);
};
return result;
};
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (a, b, c) {
showStacks();
var result = this.init(a, b, c);
mylog("======================================","","",0);
if (N_ENCRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 加密模式","","",0);
}
else if(N_DECRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 解密模式","","",0);
};
var bytes_key = b.getEncoded();
mylog(AE算法名称+"_init key:" + "|密钥" ,bytes_key,"",1);
return result;
};
cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function (a, b, c) {
showStacks();
var result = this.init(a, b, c);
if (N_ENCRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 加密模式","","",0);
}
else if(N_DECRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 解密模式","","",0);
};
return result;
};
cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function (a, b, c) {
showStacks();
var result = this.init(a, b, c);
if (N_ENCRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 加密模式","","",0);
}
else if(N_DECRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 解密模式","","",0);
};
var bytes_key = b.getEncoded();
mylog(AE算法名称+"_init key:" + "密钥:" , bytes_key,"",1);
return result;
};
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters').implementation = function (a, b, c) {
showStacks();
var result = this.init(a, b, c);
if (N_ENCRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 加密模式","","",0);
}
else if(N_DECRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 解密模式","","",0);
};
var bytes_key = b.getEncoded();
mylog(AE算法名称+"_init key:" + "密钥:" , bytes_key,"",1);
return result;
};
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom').implementation = function (a, b, c, d) {
showStacks();
var result = this.init(a, b, c, d);
if (N_ENCRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 加密模式","","",0);
}
else if(N_DECRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 解密模式","","",0);
}
var bytes_key = b.getEncoded();
mylog(AE算法名称+"_init key:" + "密钥:" , bytes_key,"",1);
return result;
};
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom').implementation = function (a, b, c, d) {
showStacks();
var result = this.update(a, b, c, d);
if (N_ENCRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 加密模式","","",0);
}
else if(N_DECRYPT_MODE == a)
{
mylog(AE算法名称+"_init | 解密模式","","",0);
};
var bytes_key = b.getEncoded();
mylog(AE算法名称+"_init key:" + "|密钥:" ,bytes_key,"",1);
return result;
};
cipher.update.overload('[B').implementation = function (a) {
showStacks();
var result = this.update(a);
mylog("======================================","","",0);
mylog(AE算法名称+"_update:" , a,"",1);
return result;
};
cipher.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
showStacks();
var result = this.update(a, b, c);
mylog("======================================","","",0);
mylog(AE算法名称+"_update: " , a , "|" + b + "|" + c,1);
return result;
};
cipher.update.overload('[B', 'int', 'int','[B').implementation = function (a, b, c,d) {
showStacks();
var result = this.update(a, b, c, d);
mylog("======================================","","",0);
mylog(AE算法名称+"_update: " , a , "|" + b + "|" + c,1);
mylog(AE算法名称+"_update:结果: " , d , "|" + b + "|" + c,1);
return result;
};
cipher.update.overload('[B', 'int', 'int','[B','int').implementation = function (a, b, c,d,e) {
showStacks();
var result = this.update(a, b, c, d,e);
mylog("======================================","","",0);
mylog(AE算法名称+"_update: " , a , "|" + b + "|" + c + "|" + e,1);
mylog(AE算法名称+"_update:结果: " , d , "|" + b + "|" + c+ "|" + e,1);
return result;
} ;
cipher.update.overload('java.nio.ByteBuffer', 'java.nio.ByteBuffer').implementation = function (a, b) {
showStacks();
var result = this.update(a,b);
mylog("======================================","","",0);
mylog(AE算法名称+"(ByteBuffer)_update: " , a.array() ,"",1);
mylog(AE算法名称+"(ByteBuffer)_update:结果: " , b.array(), "" ,1);
return result;
};
cipher.doFinal.overload().implementation = function () {
showStacks();
var result = this.doFinal();
mylog("======================================","","",0);
mylog(AE算法名称+"_doFinal结果: ",result,"",1);
return result;
};
cipher.doFinal.overload('[B').implementation = function (a) {
showStacks();
var result = this.doFinal(a);
mylog("======================================","","",0);
mylog(AE算法名称+"_doFinal参数: " ,a,"",1);
mylog(AE算法名称+"_doFinal结果: ",result,"",1);
return result;
};
cipher.doFinal.overload('[B','int').implementation = function (a,b) {
showStacks();
var result = this.doFinal(a,b);
mylog("======================================","","",0);
mylog(AE算法名称+"_doFinal结果: ", a," |"+b,1);
return result;
};
cipher.doFinal.overload('[B','int','int').implementation = function (a,b,c) {
showStacks();
var result = this.doFinal(a,b,c);
mylog("======================================","","",0);
mylog(AE算法名称+"_doFinal参数: " ,a," |"+b+"|"+c,1);
mylog(AE算法名称+"_doFinal结果: ",result,"",1);
return result;
};
cipher.doFinal.overload('[B','int','int','[B','int').implementation = function (a,b,c,d,e) {
showStacks();
var result = this.doFinal(a,b,c,d,e);
mylog("======================================","","",0);
mylog(AE算法名称+"_doFinal参数: " ,a," |"+b+"|"+c,1);
mylog(AE算法名称+"_doFinal结果: ",d," |"+e,1);
return result;
};
cipher.doFinal.overload('[B','int','int','[B').implementation = function (a,b,c,d) {
showStacks();
var result = this.doFinal(a,b,c,d);
mylog("======================================","","",0);
mylog(AE算法名称+"_doFinal参数: " ,a," |"+b+"|"+c,1);
mylog(AE算法名称+"_doFinal结果: ",d,"",1);
return result;
};
var x509EncodedKeySpec = Java.use('java.security.spec.X509EncodedKeySpec');
x509EncodedKeySpec.$init.overload('[B').implementation = function (a) {
showStacks();
var result = this.$init(a);
mylog("======================================","","",0);
mylog("RSA密钥:" + bytesToBase64(a),"","",0);
return result;
};
var rSAPublicKeySpec = Java.use('java.security.spec.RSAPublicKeySpec');
rSAPublicKeySpec.$init.overload('java.math.BigInteger', 'java.math.BigInteger').implementation = function (a, b) {
showStacks();
var result = this.$init(a, b);
mylog("======================================","","",0);
//console.log("RSA密钥:" + bytesToBase64(a));
mylog("RSA密钥N:" + a.toString(16),"","",0);
mylog("RSA密钥E:" + b.toString(16),"","",0);
return result;
};
var KeyPairGenerator = Java.use('java.security.KeyPairGenerator');
KeyPairGenerator.generateKeyPair.implementation = function ()
{
showStacks();
var result = this.generateKeyPair();
mylog("======================================","","",0);
var str_private = result.getPrivate().getEncoded();
var str_public = result.getPublic().getEncoded();
mylog("公钥 |hex:" + bytesToHex(str_public),"","",0);
mylog("私钥 |hex:" + bytesToHex(str_private),"","",0);
return result;
};
KeyPairGenerator.genKeyPair.implementation = function ()
{
showStacks();
var result = this.genKeyPair();
mylog("======================================","","",0);
var str_private = result.getPrivate().getEncoded();
var str_public = result.getPublic().getEncoded();
mylog("公钥 |hex:" + bytesToHex(str_public),"","",0);
mylog("私钥 |hex:" + bytesToHex(str_private),"","",0);
return result;
};
//返回输出流
var OutStream = Java.use('java.io.OutputStream');
OutStream['write'].overload('[B').implementation = function(data) {
showStacks();
var ret = this.write(data);
mylog("======================================","","",0);
mylog("TCP接收 输出流:",data,"" ,1);
return ret;
};
//返回输出流
OutStream['write'].overload('[B','int','int').implementation = function(data,a,b) {
showStacks();
var ret = this.write(data,a,b);
mylog("======================================","","",0);
mylog("TCP接收 输出流:",data," |"+a+"|"+b ,1);
return ret;
};
//返回输入流
var Stream = Java.use('java.io.InputStream');
Java.use("java.net.Socket").getInputStream.overload().implementation=function(){
showStacks();
mylog("tcp 输入流======================================","","",0);
var rets = this.getInputStream()
return rets;
};
Stream['read'].overload('[B').implementation = function(data) {
mylog("tcp 输入流======================================","","",0);
showStacks();
var ret = this.read(data);
mylog("======================================","","",0);
mylog("tcp 输入流:",data,"" ,1);
return ret;
};
//返回输入流
Stream['read'].overload('[B','int','int').implementation = function(data,a,b) {
mylog("tcp 输入流======================================","","",0);
showStacks();
var ret = this.read(data,a,b);
mylog("======================================","","",0);
mylog("tcp 输入流:",data," |"+a+"|"+b ,1);
return ret;
};
});
'''
return htmlstr
def mians(pakname):
print(pakname)
jscod = get_js()
process = frida.get_remote_device().attach(pakname)
script = process.create_script(jscod)
script.on("message", on_message)
script.load()
sys.stdin.read()
================================================
FILE: 第六章:安卓逆向/Frida/Frida过Root检测.js
================================================
// $ frida -l antiroot.js -U -f com.example.app --no-pause
// CHANGELOG by Pichaya Morimoto (p.morimoto@sth.sh):
// - I added extra whitelisted items to deal with the latest versions
// of RootBeer/Cordova iRoot as of August 6, 2019
// - The original one just fucked up (kill itself) if Magisk is installed lol
// Credit & Originally written by: https://codeshare.frida.re/@dzonerzy/fridantiroot/
// If this isn't working in the future, check console logs, rootbeer src, or libtool-checker.so
Java.perform(function() {
var RootPackages = ["com.noshufou.android.su", "com.noshufou.android.su.elite", "eu.chainfire.supersu",
"com.koushikdutta.superuser", "com.thirdparty.superuser", "com.yellowes.su", "com.koushikdutta.rommanager",
"com.koushikdutta.rommanager.license", "com.dimonvideo.luckypatcher", "com.chelpus.lackypatch",
"com.ramdroid.appquarantine", "com.ramdroid.appquarantinepro", "com.devadvance.rootcloak", "com.devadvance.rootcloakplus",
"de.robv.android.xposed.installer", "com.saurik.substrate", "com.zachspong.temprootremovejb", "com.amphoras.hidemyroot",
"com.amphoras.hidemyrootadfree", "com.formyhm.hiderootPremium", "com.formyhm.hideroot", "me.phh.superuser",
"eu.chainfire.supersu.pro", "com.kingouser.com", "com.android.vending.billing.InAppBillingService.COIN","com.topjohnwu.magisk"
];
var RootBinaries = ["su", "busybox", "supersu", "Superuser.apk", "KingoUser.apk", "SuperSu.apk","magisk"];
var RootProperties = {
"ro.build.selinux": "1",
"ro.debuggable": "0",
"service.adb.root": "0",
"ro.secure": "1"
};
var RootPropertiesKeys = [];
for (var k in RootProperties) RootPropertiesKeys.push(k);
var PackageManager = Java.use("android.app.ApplicationPackageManager");
var Runtime = Java.use('java.lang.Runtime');
var NativeFile = Java.use('java.io.File');
var String = Java.use('java.lang.String');
var SystemProperties = Java.use('android.os.SystemProperties');
var BufferedReader = Java.use('java.io.BufferedReader');
var ProcessBuilder = Java.use('java.lang.ProcessBuilder');
var StringBuffer = Java.use('java.lang.StringBuffer');
var loaded_classes = Java.enumerateLoadedClassesSync();
send("Loaded " + loaded_classes.length + " classes!");
var useKeyInfo = false;
var useProcessManager = false;
send("loaded: " + loaded_classes.indexOf('java.lang.ProcessManager'));
if (loaded_classes.indexOf('java.lang.ProcessManager') != -1) {
try {
//useProcessManager = true;
//var ProcessManager = Java.use('java.lang.ProcessManager');
} catch (err) {
send("ProcessManager Hook failed: " + err);
}
} else {
send("ProcessManager hook not loaded");
}
var KeyInfo = null;
if (loaded_classes.indexOf('android.security.keystore.KeyInfo') != -1) {
try {
//useKeyInfo = true;
//var KeyInfo = Java.use('android.security.keystore.KeyInfo');
} catch (err) {
send("KeyInfo Hook failed: " + err);
}
} else {
send("KeyInfo hook not loaded");
}
PackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(pname, flags) {
var shouldFakePackage = (RootPackages.indexOf(pname) > -1);
if (shouldFakePackage) {
send("Bypass root check for package: " + pname);
pname = "set.package.name.to.a.fake.one.so.we.can.bypass.it";
}
return this.getPackageInfo.call(this, pname, flags);
};
NativeFile.exists.implementation = function() {
var name = NativeFile.getName.call(this);
var shouldFakeReturn = (RootBinaries.indexOf(name) > -1);
if (shouldFakeReturn) {
send("Bypass return value for binary: " + name);
return false;
} else {
return this.exists.call(this);
}
};
var exec = Runtime.exec.overload('[Ljava.lang.String;');
var exec1 = Runtime.exec.overload('java.lang.String');
var exec2 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;');
var exec3 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;');
var exec4 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File');
var exec5 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;', 'java.io.File');
exec5.implementation = function(cmd, env, dir) {
if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {
var fakeCmd = "grep";
send("Bypass " + cmd + " command");
return exec1.call(this, fakeCmd);
}
if (cmd == "su") {
var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
send("Bypass " + cmd + " command");
return exec1.call(this, fakeCmd);
}
if (cmd == "which") {
var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
send("Bypass which command");
return exec1.call(this, fakeCmd);
}
return exec5.call(this, cmd, env, dir);
};
exec4.implementation = function(cmdarr, env, file) {
for (var i = 0; i < cmdarr.length; i = i + 1) {
var tmp_cmd = cmdarr[i];
if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {
var fakeCmd = "grep";
send("Bypass " + cmdarr + " command");
return exec1.call(this, fakeCmd);
}
if (tmp_cmd == "su") {
var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
send("Bypass " + cmdarr + " command");
return exec1.call(this, fakeCmd);
}
}
return exec4.call(this, cmdarr, env, file);
};
exec3.implementation = function(cmdarr, envp) {
for (var i = 0; i < cmdarr.length; i = i + 1) {
var tmp_cmd = cmdarr[i];
if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {
var fakeCmd = "grep";
send("Bypass " + cmdarr + " command");
return exec1.call(this, fakeCmd);
}
if (tmp_cmd == "su") {
var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
send("Bypass " + cmdarr + " command");
return exec1.call(this, fakeCmd);
}
}
return exec3.call(this, cmdarr, envp);
};
exec2.implementation = function(cmd, env) {
if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {
var fakeCmd = "grep";
send("Bypass " + cmd + " command");
return exec1.call(this, fakeCmd);
}
if (cmd == "su") {
var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
send("Bypass " + cmd + " command");
return exec1.call(this, fakeCmd);
}
return exec2.call(this, cmd, env);
};
exec.implementation = function(cmd) {
for (var i = 0; i < cmd.length; i = i + 1) {
var tmp_cmd = cmd[i];
if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {
var fakeCmd = "grep";
send("Bypass " + cmd + " command");
return exec1.call(this, fakeCmd);
}
if (tmp_cmd == "su") {
var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
send("Bypass " + cmd + " command");
return exec1.call(this, fakeCmd);
}
}
return exec.call(this, cmd);
};
exec1.implementation = function(cmd) {
if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {
var fakeCmd = "grep";
send("Bypass " + cmd + " command");
return exec1.call(this, fakeCmd);
}
if (cmd == "su") {
var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";
send("Bypass " + cmd + " command");
return exec1.call(this, fakeCmd);
}
return exec1.call(this, cmd);
};
String.contains.implementation = function(name) {
if (name == "test-keys") {
send("Bypass test-keys check");
return false;
}
return this.contains.call(this, name);
};
var get = SystemProperties.get.overload('java.lang.String');
get.implementation = function(name) {
if (RootPropertiesKeys.indexOf(name) != -1) {
send("Bypass " + name);
return RootProperties[name];
}
return this.get.call(this, name);
};
Interceptor.attach(Module.findExportByName("libc.so", "fopen"), {
onEnter: function(args) {
var path1 = Memory.readCString(args[0]);
var path = path1.split("/");
var executable = path[path.length - 1];
var shouldFakeReturn = (RootBinaries.indexOf(executable) > -1)
if (shouldFakeReturn) {
Memory.writeUtf8String(args[0], "/ggezxxx");
send("Bypass native fopen >> "+path1);
}
},
onLeave: function(retval) {
}
});
Interceptor.attach(Module.findExportByName("libc.so", "fopen"), {
onEnter: function(args) {
var path1 = Memory.readCString(args[0]);
var path = path1.split("/");
var executable = path[path.length - 1];
var shouldFakeReturn = (RootBinaries.indexOf(executable) > -1)
if (shouldFakeReturn) {
Memory.writeUtf8String(args[0], "/ggezxxx");
send("Bypass native fopen >> "+path1);
}
},
onLeave: function(retval) {
}
});
Interceptor.attach(Module.findExportByName("libc.so", "system"), {
onEnter: function(args) {
var cmd = Memory.readCString(args[0]);
send("SYSTEM CMD: " + cmd);
if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id") {
send("Bypass native system: " + cmd);
Memory.writeUtf8String(args[0], "grep");
}
if (cmd == "su") {
send("Bypass native system: " + cmd);
Memory.writeUtf8String(args[0], "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled");
}
},
onLeave: function(retval) {
}
});
/*
TO IMPLEMENT:
Exec Family
int execl(const char *path, const char *arg0, ..., const char *argn, (char *)0);
int execle(const char *path, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
int execlp(const char *file, const char *arg0, ..., const char *argn, (char *)0);
int execlpe(const char *file, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
int execv(const char *path, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
*/
BufferedReader.readLine.overload().implementation = function() {
var text = this.readLine.call(this);
if (text === null) {
// just pass , i know it's ugly as hell but test != null won't work :(
} else {
var shouldFakeRead = (text.indexOf("ro.build.tags=test-keys") > -1);
if (shouldFakeRead) {
send("Bypass build.prop file read");
text = text.replace("ro.build.tags=test-keys", "ro.build.tags=release-keys");
}
}
return text;
};
var executeCommand = ProcessBuilder.command.overload('java.util.List');
ProcessBuilder.start.implementation = function() {
var cmd = this.command.call(this);
var shouldModifyCommand = false;
for (var i = 0; i < cmd.size(); i = i + 1) {
var tmp_cmd = cmd.get(i).toString();
if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd.indexOf("mount") != -1 || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd.indexOf("id") != -1) {
shouldModifyCommand = true;
}
}
if (shouldModifyCommand) {
send("Bypass ProcessBuilder " + cmd);
this.command.call(this, ["grep"]);
return this.start.call(this);
}
if (cmd.indexOf("su") != -1) {
send("Bypass ProcessBuilder " + cmd);
this.command.call(this, ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"]);
return this.start.call(this);
}
return this.start.call(this);
};
if (useProcessManager) {
var ProcManExec = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File', 'boolean');
var ProcManExecVariant = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.lang.String', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'boolean');
ProcManExec.implementation = function(cmd, env, workdir, redirectstderr) {
var fake_cmd = cmd;
for (var i = 0; i < cmd.length; i = i + 1) {
var tmp_cmd = cmd[i];
if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") {
var fake_cmd = ["grep"];
send("Bypass " + cmdarr + " command");
}
if (tmp_cmd == "su") {
var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"];
send("Bypass " + cmdarr + " command");
}
}
return ProcManExec.call(this, fake_cmd, env, workdir, redirectstderr);
};
ProcManExecVariant.implementation = function(cmd, env, directory, stdin, stdout, stderr, redirect) {
var fake_cmd = cmd;
for (var i = 0; i < cmd.length; i = i + 1) {
var tmp_cmd = cmd[i];
if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") {
var fake_cmd = ["grep"];
send("Bypass " + cmdarr + " command");
}
if (tmp_cmd == "su") {
var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"];
send("Bypass " + cmdarr + " command");
}
}
return ProcManExecVariant.call(this, fake_cmd, env, directory, stdin, stdout, stderr, redirect);
};
}
if (useKeyInfo) {
KeyInfo.isInsideSecureHardware.implementation = function() {
send("Bypass isInsideSecureHardware");
return true;
}
}
});
================================================
FILE: 第六章:安卓逆向/Unidbg/xgorgon.java
================================================
package com.douyin;
import com.github.unidbg.*;
import com.github.unidbg.linux.android.AndroidARMEmulator;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.memory.MemoryBlock;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import java.io.File;
import java.io.IOException;
public class xgorgon extends AbstractJni {
private static LibraryResolver createLibraryResolver() {
return new AndroidResolver(23);
}
private static AndroidEmulator createARMEmulator() {
AndroidEmulator emulator = AndroidEmulatorBuilder.for32Bit().build();
return emulator;
}
private final AndroidEmulator emulator;
private final VM vm;
private final DvmClass Native;
private xgorgon() {
emulator = createARMEmulator();
final Memory memory = emulator.getMemory(); memory.setLibraryResolver(createLibraryResolver());
vm = emulator.createDalvikVM(new File("com.sun.jna"));
vm.setJni(this);
vm.setVerbose(true); // 自行修改文件路径
DalvikModule dm = vm.loadLibrary(new File("C:\\Users\\feiyi\\Desktop\\unidbg-master\\unidbg-android\\src\\test\\java\\com\\douyin\\libcms.so"), false);
dm.callJNI_OnLoad(emulator);
Native = vm.resolveClass("com/ss/sys/ces/a");
}
private void destroy() throws IOException {
emulator.close();
System.out.println("destroy"); }
public static void main(String[] args) throws Exception {
xgorgon test = new xgorgon();
test.test();
test.destroy();
}
public static String xuzi1(byte[] bArr) {
if (bArr == null) {
return null;
}
char[] charArray = "0123456789abcdef".toCharArray();
char[] cArr = new char[(bArr.length * 2)];
for (int i = 0; i < bArr.length; i++) {
int b2 = bArr[i] & 255;
int i2 = i * 2;
cArr[i2] = charArray[b2 >>> 4];
cArr[i2 + 1] = charArray[b2 & 15];
}
return new String(cArr); }
private void test() {
String methodSign = "leviathan(II[B)[B";
byte[] data = "这里是url经过处理后的data".getBytes();
int time = (int) (System.currentTimeMillis() / 1000);
Native.callStaticJniMethod(emulator, methodSign, -1,time,new ByteArray(vm,data));
Object ret = Native.callStaticJniMethodObject(emulator, methodSign, -1,time,new ByteArray(vm,data));
System.out.println("callObject执行结果:"+((DvmObject) ret).getValue());
byte[] tt = (byte[]) ((DvmObject) ret).getValue();
System.out.println(new String(tt));
String s = xuzi1(tt); System.out.println(s);
}
}
================================================
FILE: 第六章:安卓逆向/常见检测及绕过/Frida检测的处理思路.md
================================================
执行顺序:
方法一:找开源方案(10分钟找不到就方法二)
方法二:换增强版的frida-server(失败到方法三)
方法三:对应用降级。 (失败到方法四)
方法四:hook dlopen找so,删除对应so。 (失败到方法五)
方法五:正常流程分析,找检测点。
================================================
FILE: 第六章:安卓逆向/常见检测及绕过/Root检测的处理示例-1.md
================================================
# Root检测的处理示例-1
以**化妆品监管app**的root检测示例:
安装**Magisk + Shamiko**,通过magiskHide配置加入隐藏列表的进程。
1、在magisk右上角开启zygisk
2、安装隐藏root的模块 Shamiko-v0.7.3-174-release
3、设置中开启magiskHide,并配置加入隐藏列表的进程
Shamiko下载地址:[https://pan.baidu.com/s/1WjzIlHriXEhQH6SEQ9SS9g?pwd=uj7u](https://pan.baidu.com/s/1WjzIlHriXEhQH6SEQ9SS9g?pwd=uj7u)

安装配置后,可通过**化妆品监管app**测试Root是否成功隐藏。
================================================
FILE: 第六章:安卓逆向/常见检测及绕过/设备环境检测apk.md
================================================
# 环境检测apk(推荐)
## Ruru.apk
一款体积小巧、功能强大的手机检测软件,通过它用户只需动动手指便可以对手机各个模块运行状况进行检测操作,一旦发现相应的异常数据便会进行及时提醒操作。
## RiskDetector.apk
Risk Detector检测软件具备强大的检测能力,不仅能够检测手机的基础信息和root情况,还能深入分析风控风险、软件使用情况以及游戏环境等。它通过多维度的检测,确保手机的每一个环节都处于安全状态。
## Momo.apk
Momo是一款检测root与系统环境的APP,可以检测你的设备是否被root以及系统环境是否存在异常。当你的系统环境存在异常或者未对Momo隐藏root时打开Momo,Momo就会提示“环境异常”,并且会在详情里显示具体存在哪些异常项。
## Luna.apk
Luna环境检测工具app是一款专门为了安卓设备设计出来的一款检测解决方案类型人,在这款软件之中主要是用于是识别设备的硬件信息,系统的状态以及安全的风险,兼容几乎所有的机型,可以对手机型号、版本以及处理器和内存等等手机底层的数据进行检测。
## Hunter.apk
Hunter环境检测app是一款非常专业的系统监测类软件,通过这款软件应用能够很好的帮助用户完成各类监测需求,在这里更是具备了设备检测功能,能够带来不错的数据报告检测体验。
## applistdetector.apk
applistdetector应用列表检测器是一款面向安卓用户的环境与应用检测工具,用来快速识别设备上是否存在Magisk、Xposed、LSPosed、TWRP、XPrivacyLua 等可能被第三方 App 用来判定异常环境的迹象。应用将多种检测方式整合在同一页面,点击分组即可展开详细结果,并以清晰的状态图例呈现,便于安全自查、测试与排障。右下角 About 页面还提供源码链接与交流渠道入口,透明可查,适合开发者、安全从业者与进阶用户日常使用。
================================================
FILE: 第六章:安卓逆向/抖音/xposedhook.java
================================================
package com.example.xuziqiang.nanotest;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import android.text.TextUtils;
import android.content.Context;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import fi.iki.elonen.NanoHTTPD;
import java.net.URLDecoder;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.zip.GZIPOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.IOException;
import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class AwemeSrv extends NanoHTTPD {
private static final String NULL_MD5_STRING = "00000000000000000000000000000000";
private XC_LoadPackage.LoadPackageParam lpp = null;
public String sessionid="";
public AwemeSrv() {
super(18989);
}
public void init(XC_LoadPackage.LoadPackageParam lpparam) {
this.lpp = lpparam;
try {
start();
} catch (Exception e) {
XposedBridge.log("[ERR]:NanoHTTPD start error! " + e.toString());
}
}
public static byte[] xuzi(String str) {
int length = str.length();
byte[] bArr = new byte[(length / 2)];
for (int i = 0; i < length; i += 2) {
bArr[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
}
return bArr;
}
public static String xuzi1(byte[] bArr) {
if (bArr == null) {
return null;
}
char[] charArray = "0123456789abcdef".toCharArray();
char[] cArr = new char[(bArr.length * 2)];
for (int i = 0; i < bArr.length; i++) {
int b2 = bArr[i] & 255;
int i2 = i * 2;
cArr[i2] = charArray[b2 >>> 4];
cArr[i2 + 1] = charArray[b2 & 15];
}
return new String(cArr);
}
public byte[] get_leviathan(int i,int time, byte[] s){
return (byte[]) XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.ss.sys.ces.a", lpp.classLoader), "" + "" + "", i, time, s);
}
public static String parseStrToMd5L32(byte[] str){
String reStr = null;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest(str);
StringBuffer stringBuffer = new StringBuffer();
for (byte b : bytes){
int bt = b&0xff;
if (bt < 16){
stringBuffer.append(0);
}
stringBuffer.append(Integer.toHexString(bt));
}
reStr = stringBuffer.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return reStr;
}
public byte[] get_ttencrypt(XC_LoadPackage.LoadPackageParam lpp2, byte[] data, int length) {
return (byte[]) XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.bytedance.frameworks.encryptor.EncryptorUtil", lpp2.classLoader), "a", data, length);
}
public byte[] get_formdata(byte[] data) throws Exception{
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(8192);
GZIPOutputStream gZIPOutputStream = new GZIPOutputStream(byteArrayOutputStream);
gZIPOutputStream.write(data);
gZIPOutputStream.close();
byte[] bArr2 = byteArrayOutputStream.toByteArray();
return get_ttencrypt(this.lpp, bArr2, bArr2.length);
}
public String get_stub(byte[] barr) throws Exception{
String reStr = parseStrToMd5L32(barr);
reStr = reStr.toUpperCase();
return reStr;
}
public String get_fed(String fed) throws Exception{
return (String) XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.ss.a.b.d", lpp.classLoader), "a", fed);
}
public String get_device(String url, String formdata) throws Exception {
byte[] data = formdata.getBytes();
byte[] barr = get_formdata(data);
String stub = get_stub(barr);
int time = (int) (System.currentTimeMillis() / 1000);
long time1 = System.currentTimeMillis();
int indexOf = url.indexOf("?");
String fed = url.substring(indexOf + 1);
String x = get_fed(fed);
byte[] s = xuzi(x + x + NULL_MD5_STRING + NULL_MD5_STRING);
int i = -1;
byte[] gon = get_leviathan(i, time, s);
String x_gon = xuzi1(gon);
JSONObject json_obj = new JSONObject();
json_obj.put("X-SS-STUB", stub);
json_obj.put("X-SS-REQ-TICKET", time1);
json_obj.put("X-Gorgon", x_gon);
json_obj.put("X-Khronos", time);
String isoString = new String(barr, "ISO-8859-1");
json_obj.put("form", isoString);
return json_obj.toString();
}
private static String getUrl(String url, String stub, long time1, String x_gon, int time, byte[] barr) {
String s2 = new String(barr);
Authenticator.setDefault(new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(ProxyUser, ProxyPass.toCharArray());
}
});
String doc = null;
try {
doc = Jsoup
.connect(url)
.ignoreContentType(true)
.ignoreHttpErrors(true)
.timeout(3000)
.userAgent("okhttp/3.10.0.1")
.header("X-SS-STUB", stub+"")
.header("X-SS-QUERIES", "")
.header("X-SS-REQ-TICKET", time1+"")
.header("X-Gorgon", x_gon+"")
.header("X-Khronos", time+"")
.header("Content-Type", "application/octet-stream;tt-data=a")
.header("Host", "log.snssdk.com")
.requestBody(s2)
// .data(s2)
.post().text();
if (doc != null) {
return doc;
}
} catch (IOException e) {
e.printStackTrace();
}
finally {
XposedBridge.log("X-SS-STUB " + stub);
XposedBridge.log("x_gon " + x_gon);
XposedBridge.log("url " + url);
XposedBridge.log("s2 " + s2);
return null;
}
}
public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
String msg = "";
Map parms = session.getParms();
if (parms.get("url") == null && parms.get("formdata") == null) {
String msg2 = msg + "Aweme Server
\n";
msg = msg2 + "";
} else {
try {
String url = URLDecoder.decode(parms.get("url"), "utf-8");
String formdata = URLDecoder.decode(parms.get("formdata"), "utf-8");
msg = msg + get_device(url, formdata);
} catch (Exception e) {
XposedBridge.log(e.toString());
}
}
return newFixedLengthResponse(msg);
}
}
================================================
FILE: 第十一章:反爬虫补充/11.1 css动态字体反爬/选哪儿网动态字体.py
================================================
# -*- coding: utf-8 -*-
import requests
import re
headers = {
'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',
'origin': 'https://www.xuannaer.com',
'referer': 'https://www.xuannaer.com/',
'sec-fetch-dest': 'font',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-site'
}
doc = requests.get('https://www.xuannaer.com/zhaopaigua',headers=headers).text
# 这个链接会更新,注意下
woff = re.findall('https://img2.xuanzhi.com/static/new/fonts/\w{16}/font.woff\?\d{11}',doc,re.S)[0]
print(woff)
woff_bytes = requests.get(woff,headers=headers,allow_redirects=True)
with open('zhaopaigua.woff','wb') as f:
f.write(woff_bytes.content)
from fontTools.ttLib import TTFont
font = TTFont('zhaopaigua.woff')
font.saveXML('zhaopaigua.xml')
f = open('zhaopaigua.xml','r',encoding='utf-8')
document = f.read()
f.close()
cmap = re.findall('',document,re.S)
item = {}
for node in cmap:
item[node[1]] = chr(eval(node[0]))
GlyphID = re.findall('',document,re.S)[1:]
# 只要数字 取0-9 前10个元素
result = {}
for li in GlyphID[:10]:
num = int(li[0])-1 # 正确的数字
result[item[li[1]]]=num
print(result)
================================================
FILE: 第十一章:反爬虫补充/11.2 tls指纹识别/aiohttp_ja3.py
================================================
import random
import ssl
# aiohttp 修改 ja3
class DESAdapter():
def __init__(self):
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')
def __call__(self):
CIPHERS = self.ORIGIN_CIPHERS.split(':')
random.shuffle(CIPHERS)
CIPHERS = ':'.join(CIPHERS)
CIPHERS = CIPHERS + ':!aNULL:!eNULL:!MD5'
context = ssl.create_default_context()
context.set_ciphers(CIPHERS)
return context
import aiohttp,asyncio
async def main():
async with aiohttp.ClientSession() as session:
for req in range(5):
async with session.get("https://ja3er.com/json",ssl=Adapter()) as res:
data = await res.json()
print(data)
if __name__ == '__main__':
Adapter = DESAdapter()
m = asyncio.get_event_loop()
m.run_until_complete(main())
================================================
FILE: 第十一章:反爬虫补充/11.2 tls指纹识别/requests_jar3.py
================================================
from requests.adapters import HTTPAdapter
from urllib3.util.ssl_ import create_urllib3_context
import random,requests
class DESAdapter(HTTPAdapter):
def __init__(self, *args, **kwargs):
self.CIPHERS = self.get_ciphers()
super().__init__(*args, **kwargs)
def get_ciphers(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')
CIPHERS = ORIGIN_CIPHERS.split(':')
random.shuffle(CIPHERS)
CIPHERS = ':'.join(CIPHERS)
CIPHERS = CIPHERS + ':!aNULL:!eNULL:!MD5'
return CIPHERS
def init_poolmanager(self, *args, **kwargs):
context = create_urllib3_context(ciphers=self.CIPHERS)
kwargs['ssl_context'] = context
return super(DESAdapter, self).init_poolmanager(*args, **kwargs)
if __name__ == '__main__':
sess = requests.Session()
while 1:
sess.mount('https://ja3er.com', DESAdapter())
res = sess.get('https://ja3er.com/json').json()
print(res)
================================================
FILE: 第十一章:反爬虫补充/11.2 tls指纹识别/scrapy_Ja3_download.py
================================================
# -*- coding: utf-8 -*-
from typing import Optional
import random
import ssl
from twisted.internet.defer import Deferred
from scrapy import signals
from scrapy.http import Request, Response, Headers
from scrapy.spiders import Spider
from scrapy.settings import Settings
from scrapy.crawler import Crawler
from scrapy.utils.defer import deferred_from_coro, deferred_f_from_coro_f
from scrapy.responsetypes import responsetypes
from scrapy.core.downloader.handlers.http import HTTPDownloadHandler
import aiohttp
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')
class SSLFactory:
def __init__(self):
self.ciphers = ORIGIN_CIPHERS.split(":")
def __call__(self) -> ssl.SSLContext:
random.shuffle(self.ciphers)
ciphers = ":".join(self.ciphers)
ciphers = ciphers + ":!aNULL:!eNULL:!MD5"
context = ssl.create_default_context()
context.set_ciphers(ciphers)
return context
sslgen = SSLFactory()
class Ja3DownloadHandler(HTTPDownloadHandler):
def __init__(self, settings: Settings, crawler: Optional[Crawler] = None):
super().__init__(settings, crawler)
#super().__init__(settings)
self.client = None
crawler.signals.connect(self._engine_started, signals.engine_started)
@deferred_f_from_coro_f
async def _engine_started(self, signal, sender):
client = aiohttp.ClientSession()
self.client = await client.__aenter__()
def download_request(self, request: Request, spider: Spider) -> Deferred:
if request.meta.get("ja3"): # 注意大小写
return deferred_from_coro(self._download_request(request, spider))
return super().download_request(request, spider) # 普通下载
async def _download_request(self, request: Request, spider: Spider) -> Response:
"""aiohttp下载逻辑"""
async with self.client.request(request.method,
request.url,
data=request.body,
headers=request.headers.to_unicode_dict(),
cookies=request.cookies,
ssl=sslgen()) as response:
headers = Headers(response.headers)
body = await response.read()
respcls = responsetypes.from_args(headers=headers,
url=str(response.url),
body=body)
return respcls(url=str(response.url),
status=response.status,
headers=headers,
body=body,
flags=["ja3"],
request=request,
protocol=response.version)
@deferred_f_from_coro_f
async def close(self):
await self.client.__aexit__(None, None, None)
await super().close()
================================================
FILE: 第十一章:反爬虫补充/11.3 http2/scrapy_http2_download.py
================================================
# -*- coding: utf-8 -*-
from typing import Optional
from twisted.internet.defer import Deferred
from scrapy import signals
from scrapy.http import Request, Response, Headers
from scrapy.spiders import Spider
from scrapy.settings import Settings
from scrapy.crawler import Crawler
from scrapy.utils.defer import deferred_from_coro, deferred_f_from_coro_f
from scrapy.responsetypes import responsetypes
from scrapy.core.downloader.handlers.http import HTTPDownloadHandler
import httpx
class HttpxDownloadHandler(HTTPDownloadHandler):
def __init__(self, settings: Settings, crawler: Optional[Crawler] = None):
super().__init__(settings, crawler)
self.client = None
crawler.signals.connect(self._engine_started, signals.engine_started)
@deferred_f_from_coro_f
async def _engine_started(self, signal, sender):
client = httpx.AsyncClient(http2=True)
self.client = await client.__aenter__()
def download_request(self, request: Request, spider: Spider) -> Deferred:
if request.meta.get("h2"):
return deferred_from_coro(self._download_request(request, spider))
return super().download_request(request, spider) # 普通下载
async def _download_request(self, request: Request, spider: Spider) -> Response:
"""httpx下载逻辑"""
response = await self.client.request(request.method,
request.url,
content=request.body,
headers=request.headers.to_unicode_dict(),
cookies=request.cookies)
headers = Headers(response.headers)
respcls = responsetypes.from_args(headers=headers,
url=response.url,
body=response.content)
return respcls(url=str(response.url),
status=response.status_code,
headers=headers,
body=response.content,
flags=["httpx"],
request=request,
protocol=response.http_version)
@deferred_f_from_coro_f
async def close(self):
await self.client.__aexit__()
await super().close()
================================================
FILE: 第十章:验证码识别技术/10.2.1.1 邮箱滑块验证码.py
================================================
from selenium import webdriver
from io import BytesIO
import cv2,numpy as np, random, requests, time
from selenium.webdriver import ActionChains
import warnings
from PIL import Image
warnings.filterwarnings("ignore",category=DeprecationWarning)
'''识别缺口位置、计算偏移值'''
class SlideCrack(object):
def __init__(self, gap, bg, out=None):
"""
init code
:param gap: 缺口图片
:param bg: 背景图片
:param out: 输出图片
"""
self.gap = gap
self.bg = bg
self.out = out
@staticmethod
def clear_white(img):
# 清除图片的空白区域,这里主要清除滑块的空白
img = cv2.imdecode(np.frombuffer(img,np.uint8), cv2.IMREAD_UNCHANGED)
rows, cols, channel = img.shape
min_x = 255
min_y = 255
max_x = 0
max_y = 0
for x in range(1, rows):
for y in range(1, cols):
t = set(img[x, y])
if len(t) >= 2:
if x <= min_x:
min_x = x
elif x >= max_x:
max_x = x
if y <= min_y:
min_y = y
elif y >= max_y:
max_y = y
img1 = img[min_x:max_x, min_y: max_y]
return img1
def template_match(self, tpl, target):
th, tw = tpl.shape[:2]
result = cv2.matchTemplate(target, tpl, cv2.TM_CCOEFF_NORMED)
# 寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
tl = max_loc
# br = (tl[0] + tw, tl[1] + th)
# 绘制矩形边框,将匹配区域标注出来
# target:目标图像
# tl:矩形定点
# br:矩形的宽高
# (0,0,255):矩形边框颜色
# 1:矩形边框大小
# cv2.rectangle(target, tl, br, (0, 0, 255), 2)
# if self.out:
# cv2.imwrite(self.out, target)
return tl[0]
@staticmethod
def image_edge_detection(img):
edges = cv2.Canny(img, 100, 200)
return edges
def discern(self):
img1 = self.clear_white(self.gap)
img1 = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY)
slide = self.image_edge_detection(img1)
back = cv2.cvtColor(np.asarray(Image.open(BytesIO(self.bg))), cv2.COLOR_RGB2GRAY)
back = self.image_edge_detection(back)
slide_pic = cv2.cvtColor(slide, cv2.COLOR_GRAY2RGB)
back_pic = cv2.cvtColor(back, cv2.COLOR_GRAY2RGB)
x = self.template_match(slide_pic, back_pic) # 滑块偏移值
# 输出横坐标, 即 滑块在图片上的位置
return x
def get_distance(gap, bg):
"""
计算滑动距离
"""
with open(gap,'rb') as f:
gap = f.read()
with open(bg,'rb') as f:
bg = f.read()
sc = SlideCrack(gap, bg, "image/r.png")
distance = int(sc.discern() // 2.4)
return distance
'''模拟验证行为'''
def main():
driver = webdriver.Chrome(executable_path=r'chromedriver.exe')
driver.get('https://mail.qq.com')
time.sleep(1)
driver.switch_to.frame("login_frame")
time.sleep(1)
driver.find_element_by_id('switcher_plogin').click()
username = '1234567{}@qq.com'.format(random.randint(0, 99))
driver.find_element_by_id("u").send_keys(username)
driver.find_element_by_id("p").send_keys('wwwwwwwww')
time.sleep(1)
driver.find_element_by_id("login_button").click()
time.sleep(1)
driver.switch_to.frame(driver.find_element_by_id('tcaptcha_iframe'))
time.sleep(1)
src_big = driver.find_element_by_id('slideBg').get_attribute('src')
time.sleep(1)
src_small = driver.find_element_by_id('slideBlock').get_attribute('src')
img_big = requests.get(src_big).content
img_small = requests.get(src_small).content
with open('image/yanzhengtu.jpg', 'wb') as f:
f.write(img_big)
with open('image/huakuai.png', 'wb') as f:
f.write(img_small)
y = get_distance('image/huakuai.png','image/yanzhengtu.jpg')
time.sleep(2)
huakuai = driver.find_element_by_id('tcaptcha_drag_thumb')
action = ActionChains(driver)
action.click_and_hold(huakuai).perform()
action.move_by_offset(y-30, 0).perform()
action.release(on_element=huakuai).perform()
time.sleep(3)
driver.close()
if __name__ == '__main__':
main()
================================================
FILE: 第十章:验证码识别技术/10.2.1.2 邮箱滑块验证码.py
================================================
# -*- coding: utf-8 -*-
import re
from selenium import webdriver
import cv2, numpy as np, random, requests, time
from selenium.webdriver import ActionChains
import warnings
from PIL import Image
warnings.filterwarnings("ignore",category=DeprecationWarning)
from io import BytesIO
huakuai_path = 'huakuai.png'
yanzheng_path = 'yanzhengtu.jpg'
'''识别缺口位置、计算偏移值'''
class SlideCrack(object):
def __init__(self, gap, bg, out=None):
"""
init code
:param gap: 缺口图片
:param bg: 背景图片
:param out: 输出图片
"""
self.gap = gap
self.bg = bg
self.out = out
@staticmethod
def clear_white(img):
# 清除图片的空白区域,这里主要清除滑块的空白
img = cv2.imdecode(np.frombuffer(img,np.uint8), cv2.IMREAD_UNCHANGED)
rows, cols, channel = img.shape
min_x = 255
min_y = 255
max_x = 0
max_y = 0
for x in range(1, rows):
for y in range(1, cols):
t = set(img[x, y])
if len(t) >= 2:
if x <= min_x:
min_x = x
elif x >= max_x:
max_x = x
if y <= min_y:
min_y = y
elif y >= max_y:
max_y = y
img1 = img[min_x:max_x, min_y: max_y]
return img1
def template_match(self, tpl, target):
th, tw = tpl.shape[:2]
result = cv2.matchTemplate(target, tpl, cv2.TM_CCOEFF_NORMED)
# 寻找矩阵(一维数组当作向量,用Mat定义) 中最小值和最大值的位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
tl = max_loc
# br = (tl[0] + tw, tl[1] + th)
# 绘制矩形边框,将匹配区域标注出来
# target:目标图像
# tl:矩形定点
# br:矩形的宽高
# (0,0,255):矩形边框颜色
# 1:矩形边框大小
# cv2.rectangle(target, tl, br, (0, 0, 255), 2)
# if self.out:
# cv2.imwrite(self.out, target)
return tl[0]
@staticmethod
def image_edge_detection(img):
edges = cv2.Canny(img, 100, 200)
return edges
def discern(self):
img1 = self.clear_white(self.gap)
img1 = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY)
slide = self.image_edge_detection(img1)
back = cv2.cvtColor(np.asarray(Image.open(BytesIO(self.bg))), cv2.COLOR_RGB2GRAY)
back = self.image_edge_detection(back)
slide_pic = cv2.cvtColor(slide, cv2.COLOR_GRAY2RGB)
back_pic = cv2.cvtColor(back, cv2.COLOR_GRAY2RGB)
x = self.template_match(slide_pic, back_pic) # 滑块偏移值
# 输出横坐标, 即 滑块在图片上的位置
return x
def get_distance(gap, bg):
"""
计算滑动距离
"""
with open(gap,'rb') as f:
gap = f.read()
with open(bg,'rb') as f:
bg = f.read()
sc = SlideCrack(gap, bg, "33.png")
distance = int(sc.discern() // 2.4)
return distance
'''selenium模拟登陆 获取滑块'''
def main():
driver = webdriver.Chrome(executable_path= r'chromedriver.exe')
driver.get('https://mail.qq.com')
time.sleep(2)
driver.switch_to.frame("login_frame")
try:
driver.find_element_by_id('switcher_plogin').click()
except:
pass
username = '1234567{}@qq.com'.format(random.randint(0, 99))
driver.find_element_by_id("u").send_keys(username)
driver.find_element_by_id("p").send_keys('wwwwwwwww')
time.sleep(2)
driver.find_element_by_id("login_button").click()
time.sleep(2)
frame = driver.find_element_by_id('tcaptcha_iframe_dy')
driver.switch_to.frame(frame)
time.sleep(1)
if driver.find_element_by_id('slideBgWrap'):
time.sleep(0.5)
src_big = driver.find_element_by_id('slideBg').get_attribute('style')
src_big = 'https://t.captcha.qq.com'+''.join(re.findall('(/cap_union_new_getcapbysig\?.*?)"\);',src_big,re.S))
src_small = driver.find_element_by_xpath('//*[@id="tcOperation"]/div[8]').get_attribute('style')
src_small = 'https://t.captcha.qq.com'+''.join(re.findall('(/cap_union_new_getcapbysig\?.*?)"\);',src_small,re.S))
img_big = requests.get(src_big).content
img_small = requests.get(src_small).content
with open(yanzheng_path, 'wb') as f:
f.write(img_big)
with open(huakuai_path, 'wb') as f:
f.write(img_small)
# 切割图片 提取滑块
from PIL import Image
img = Image.open(huakuai_path)
region = img.crop((162, 514, 250, 588)) ## 0,0表示要裁剪的位置的左上角坐标,50,50表示右下角。
region.save(huakuai_path)
y = get_distance(huakuai_path,yanzheng_path)
huakuai = driver.find_element_by_xpath('//*[@id="tcOperation"]/div[6]')
action = ActionChains(driver)
action.click_and_hold(huakuai).perform()
action.move_by_offset(y-30, 0).perform()
action.release(on_element=huakuai).perform()
time.sleep(3)
driver.close()
if __name__ == '__main__':
main()
================================================
FILE: 第十章:验证码识别技术/10.2.2 数美滑块验证码.py
================================================
"""
数美滑块验证码验证
"""
import base64
import json
import random
import re
import time
from io import BytesIO
import cv2
import numpy as np
import requests
from pyDes import des, ECB
CAPTCHA_DISPLAY_WIDTH = 310
CAPTCHA_DISPLAY_HEIGHT = 155
p = {}
def pad(b):
"""
块填充
"""
block_size = 8
while len(b) % block_size:
b += b'\0'
return b
def split_args(s):
"""
分割js参数
"""
r = []
a = ''
i = 0
while i < len(s):
c = s[i]
if c == ',' and (a[0] != '\'' or len(a) >= 2 and a[-1] == '\''):
r.append(a)
a = ''
elif c:
a += c
i += 1
r.append(a)
return r
def find_arg_names(script):
"""
通过js解析出参数名
"""
names = {}
a = []
for r in re.findall(r'function\((.*?)\)', script):
if len(r.split(',')) > 100:
a = split_args(r)
break
r = re.search(r';\)(.*?)\(}', script[::-1]).group(1)
v = split_args(r[::-1])
d = r'{%s}' % ''.join([((',' if i else '') + '\'k{}\':([_x0-9a-z]*)'.format(i + 1)) for i in range(15)])
k = []
r = re.search(d, script)
for i in range(15):
k.append(r.group(i + 1))
n = int(v[a.index(re.search(r'arguments;.*?,(.*?)\);', script).group(1))], base=16)
for i in range(n // 2):
v[i], v[n - 1 - i] = v[n - 1 - i], v[i]
for i, b in enumerate(k):
t = v[a.index(b)].strip('\'')
names['k{}'.format(i + 1)] = t if len(t) > 2 else t[::-1]
return names
def get_encrypt_content(message, key, flag):
"""
接口参数的加密、解密
"""
des_obj = des(key.encode(), mode=ECB)
if flag:
content = pad(str(message).replace(' ', '').encode())
return base64.b64encode(des_obj.encrypt(content)).decode('utf-8')
else:
return des_obj.decrypt(base64.b64decode(message)).decode('utf-8')
def get_random_ge(distance):
"""
生成随机的轨迹
"""
ge = []
y = 0
v = 0
t = 1
current = 0
mid = distance * 3 / 4
exceed = 20
z = t
ge.append([0, 0, 1])
while current < (distance + exceed):
if current < mid / 2:
a = 15
elif current < mid:
a = 20
else:
a = -30
a /= 2
v0 = v
s = v0 * t + 0.5 * a * (t * t)
current += int(s)
v = v0 + a * t
y += random.randint(-5, 5)
z += 100 + random.randint(0, 10)
ge.append([min(current, (distance + exceed)), y, z])
while exceed > 0:
exceed -= random.randint(0, 5)
y += random.randint(-5, 5)
z += 100 + random.randint(0, 10)
ge.append([min(current, (distance + exceed)), y, z])
return ge
def make_mouse_action_args(distance):
"""
生成鼠标行为相关的参数
"""
ge = get_random_ge(distance)
args = {
p['k']['k5']: round(distance / CAPTCHA_DISPLAY_WIDTH, 2),
p['k']['k6']: get_random_ge(distance),
p['k']['k7']: ge[-1][-1] + random.randint(0, 100),
p['k']['k8']: CAPTCHA_DISPLAY_WIDTH,
p['k']['k9']: CAPTCHA_DISPLAY_HEIGHT,
p['k']['k11']: 1,
p['k']['k12']: 0,
p['k']['k13']: -1,
'act.os': 'android'
}
return args
def get_distance(fg, bg):
"""
计算滑动距离
"""
target = cv2.imdecode(np.asarray(bytearray(fg.read()), dtype=np.uint8), 0)
template = cv2.imdecode(np.asarray(bytearray(bg.read()), dtype=np.uint8), 0)
result = cv2.matchTemplate(target, template, cv2.TM_CCORR_NORMED)
_, distance = np.unravel_index(result.argmax(), result.shape)
return distance
def update_protocol(protocol_num, js_uri):
"""
更新协议
"""
global p
r = requests.get(js_uri, verify=False)
names = find_arg_names(r.text)
p = {
'i': protocol_num,
'k': names
}
def conf_captcha(organization):
"""
获取验证码设置
"""
url = 'https://captcha.fengkongcloud.com/ca/v1/conf'
args = {
'organization': organization,
'model': 'slide',
'sdkver': '1.1.3',
'rversion': '1.0.3',
'appId': 'default',
'lang': 'zh-cn',
'channel': 'YingYongBao',
'callback': 'sm_{}'.format(int(time.time() * 1000))
}
r = requests.get(url, params=args, verify=False)
resp = json.loads(re.search(r'{}\((.*)\)'.format(args['callback']), r.text).group(1))
return resp
def register_captcha(organization):
"""
注册验证码
"""
url = 'https://captcha.fengkongcloud.com/ca/v1/register'
args = {
'organization': organization,
'channel': 'YingYongBao',
'lang': 'zh-cn',
'model': 'slide',
'appId': 'default',
'sdkver': '1.1.3',
'data': '{}',
'rversion': '1.0.3',
'callback': 'sm_{}'.format(int(time.time() * 1000))
}
r = requests.get(url, params=args, verify=False)
resp = json.loads(re.search(r'{}\((.*)\)'.format(args['callback']), r.text).group(1))
return resp
def verify_captcha(organization, rid, key, distance):
"""
提交验证
"""
url = 'https://captcha.fengkongcloud.com/ca/v2/fverify'
args = {
'organization': organization,
p['k']['k1']: 'default',
p['k']['k2']: 'YingYongBao',
p['k']['k3']: 'zh-cn',
'rid': rid,
'rversion': '1.0.3',
'sdkver': '1.1.3',
'protocol': p['i'],
'ostype': 'web',
'callback': 'sm_{}'.format(int(time.time() * 1000))
}
args.update(make_mouse_action_args(distance))
key = get_encrypt_content(key, 'sshummei', 0)
for k, v in args.items():
if len(k) == 2:
args[k] = get_encrypt_content(v, key, 1)
print(args)
r = requests.get(url, params=args, verify=False)
resp = json.loads(re.search(r'{}\((.*)\)'.format(args['callback']), r.text).group(1))
return resp
def get_verify(organization):
"""
进行验证
"""
resp = conf_captcha(organization)
protocol_num = re.search(r'build/v1.0.3-(.*?)/captcha-sdk.min.js', resp['detail']['js']).group(1)
if not p.get('id') or protocol_num != p['i']:
update_protocol(protocol_num, ''.join(['https://', resp['detail']['domains'][0], resp['detail']['js']]))
resp = register_captcha(organization)
rid = resp['detail']['rid']
key = resp['detail']['k']
domain = resp['detail']['domains'][0]
fg_uri = resp['detail']['fg']
bg_uri = resp['detail']['bg']
fg_url = ''.join(['http://', domain, fg_uri])
bg_url = ''.join(['http://', domain, bg_uri])
r = requests.get(fg_url, verify=False)
fg = BytesIO(r.content)
r = requests.get(bg_url, verify=False)
bg = BytesIO(r.content)
distance = get_distance(fg, bg)
print(distance)
r = verify_captcha(organization, rid, key, int(distance / 600 * 310))
return rid, r
def test():
# 表示小红书
organization = 'eR46sBuqF0fdw7KWFLYa'
# rid是验证过程中响应的标示,r是最后提交验证返回的响应
rid, r = get_verify(organization)
print(rid, r)
# riskLevel为PASS说明验证通过
if r['riskLevel'] == 'PASS':
# 这里需要提交rid
# 具体可抓包查看,接口:/api/sns/v1/system_service/slide_captcha_check
pass
if __name__ == '__main__':
test()
================================================
FILE: 第四章:自动化工具的应用/4.2.4 Pyppeteer拦截器/test.js
================================================
var request = require('request');
const puppeteer = require("puppeteer-extra");
const StealthPlugin = require("puppeteer-extra-plugin-stealth");
puppeteer.use(StealthPlugin());
var apage;
var message_js = "js content";
puppeteer.launch({
userDataDir: "data",
ignoreDefaultArgs: ["--enable-automation"],
headless: false,
}).then(browser => {
browser.newPage().then((page) => {
apage = page;
page.setRequestInterception(true).then(() => {
page.on('request',async (req) => {
if (req.url().indexOf("https://www.lx.js") != -1) {
req.respond({
status:200,
headers:{},
body:message_js
})
}
else if (req.url().indexOf("https://www.lx.png") != -1) {
req.abort()
}
page.on('response', async response => {
if (response.url().indexOf("https://www.lx.json/") != -1) {
let message = response.text();
message.then(res =>{
console.log(res)
})
.catch(err =>{
console.log(err)
})
}
})
req.continue();
});
})
page.goto("https://www.lx.com")
}, {waitUntil: "networkidle0"}).then(() => {
})
});
================================================
FILE: 第四章:自动化工具的应用/4.2.4 Pyppeteer拦截器/test.py
================================================
import asyncio
from pyppeteer import launch
async def main():
browser = await launch()
page = await browser.newPage()
# 设置 request 拦截器
await page.setRequestInterception(True)
page.on('request', lambda req: asyncio.ensure_future(intercept_request(req)))
# 设置 response 拦截器
page.on('response', lambda rep: asyncio.ensure_future(intercept_response(rep)))
await page.goto('https://www.baidu.com')
await browser.close()
# 请求拦截器
async def intercept_request(Request):
if Request.url=='':
# 跳转url
await Request.continue_({"url": ""})
elif Request.url =='':
# 停止请求
await Request.abort()
elif Request.url =='':
# 用给定的响应内容完成请求
await Request.respond({"status":"","body":""})
else:
# 保持请求
await Request.continue_()
# 响应拦截器
async def intercept_response(Response):
print(Response.url)
if Response.url=="https://www.baidu.com":
response = await Response.text()
...
asyncio.get_event_loop().run_until_complete(main())
================================================
FILE: 第四章:自动化工具的应用/4.3.5 cefpython3爬虫实战/cefpython_demo.py
================================================
import sys
import threading
from cefpython3 import cefpython as cef
# 代码转自 https://blog.csdn.net/jianshen_5465/article/details/118699364
# 代码转自 https://segmentfault.com/a/1190000021672729?utm_source=tag-newest
sys.excepthook = cef.ExceptHook
class ClientHandler(object):
r""" 自定义客户端 Handler """
def __init__(self, chromeObject):
self.chrome = chromeObject
def GetViewRect(self, rect_out, **kwargs):
r""" 渲染接口 """
# [x, y, width, height]
rect_out.extend([0, 0, self.chrome.width, self.chrome.height])
return True
def OnConsoleMessage(self, browser, message, **kwargs):
r""" 浏览器控制台接口 """
self.chrome.console.append(message)
def OnLoadError(self, browser, frame, error_code, failed_url, **_):
self.chrome.ready = error_code
self.chrome._getReadyLock.acquire()
self.chrome._getReadyLock.notify()
self.chrome._getReadyLock.release()
def OnLoadingStateChange(self, browser, is_loading, **kwargs):
r""" 加载接口,当浏览器加载状态变化时调用 """
if is_loading:
# 加载中
self.chrome.ready = False
else:
# 加载完成
self.chrome.ready = True
self.chrome._getReadyLock.acquire()
self.chrome._getReadyLock.notify()
self.chrome._getReadyLock.release()
class Client(object):
def __init__(self, width=1920, height=1080, headless=False):
self.width = width
self.height = height
self.headless = headless
self.console = []
self.browser = None
self.source = None
self.domArray = None
self.windowParams = None
self.ready = True
self._getSourceLock = threading.Condition()
self._getDOMLock = threading.Condition()
self._getReadyLock = threading.Condition()
self._handler = ClientHandler(self)
settings,switches = {},{}
if self.headless:
settings['windowless_rendering_enabled'] = True
cef.Initialize(settings=settings, switches=switches)
def __getattr__(self, name):
r""" 将所有未知的属性和方法传递给 CEF 浏览器 """
return getattr(self.browser, name)
def getBrowser(self):
if self.browser:
return self.browser
# 创建浏览器实例
if self.headless:
parent_handle = 0
wininfo = cef.WindowInfo()
wininfo.SetAsOffscreen(parent_handle)
self.browser = cef.CreateBrowserSync(window_info=wininfo)
else:
self.browser = cef.CreateBrowserSync()
self.browser.SetClientHandler(self._handler)
self.browser.SendFocusEvent(True)
self.browser.WasResized() # 在 headless 模式下应至少调用一次这个方法
return self
def LoadUrl(self, url, synchronous=False):
r""" 将 URL 传递给浏览器 """
self.ready = False
self.browser.LoadUrl(url)
if synchronous: # 同步方式
self._getReadyLock.acquire()
if not self.ready:
self._getReadyLock.wait()
self._getReadyLock.release()
def getSource(self, synchronous=False):
r""" 返回 main frame 的 html 源码, """
self.source = None
self.browser.GetMainFrame().GetSource(self)
if synchronous:
self._getSourceLock.acquire()
if not self.source:
# 等待 Visit 函数准备好 source 的通知
self._getSourceLock.wait()
self._getSourceLock.release()
return self.source
def Visit(self, value):
r"StringVisitor 接口"
self.source = value
self._getSourceLock.acquire()
self._getSourceLock.notify()
self._getSourceLock.release()
def BrowserThread(browser):
r""" 线程入口函数 """
browser.ready = False
browser.LoadUrl(url, True) # True 为同步调用
with open('source.html', mode='w', encoding='utf8') as srcfp:
source = browser.getSource(True) # 同步获取
assert(source)
srcfp.write(source)
browser.CloseBrowser()
if __name__ == '__main__':
url = 'http://www.baidu.com'
browser = Client(width=640, height=480).getBrowser()
browserThread = threading.Thread(target=BrowserThread, args=(browser,))
browserThread.start()
cef.MessageLoop()
browserThread.join()
browser = None
cef.Shutdown()
================================================
FILE: 第四章:自动化工具的应用/4.7.3 autojs指数查询案例/main.js
================================================
// toast('Hello, Auto.js');
app.launchApp('微信');
//返回到首页
function goToHomePage(){
let k = 0;
while(k < 30){
k = k + 1;
if(text("微信").depth(10).exists()){
//要支持的动作
toast('已到首页');
break;
}else{
back();
sleep(1000*0.2);
}
}
}
// goToHomePage()
// exit();
//前往公众号搜索
function goToSearchPage(){
//搜索按钮
var it = className("android.widget.ImageView").depth(17).findOne();
var b = it.bounds();
click(b.centerX(), b.centerY());
sleep(500);
text('公众号').click();
sleep(1000);
text('公众号').click();
}
//获取界面上的搜索结果
function getSearchResult(saveArray){
sleep(500);
let tList = depth(18).find();//从第 18 级开始取元素
for(let i=0;tList && i 0){
let indexInParent = tList[i].indexInParent();// 搜索出来第几个 索引
// toastLog('索引:' + indexInParent);sleep(1000*0.5);
let cell = tList[i].child(0);// 19
if(cell && cell.childCount() > 2){
cell = cell.child(2);//20
let title = '';
let desc = '';
if(cell.childCount() >= 3){
title = cell.child(1).text();//21
desc = cell.child(2).text();//21
}else{
title = cell.child(0).text();//21
desc = cell.child(1).text();//21
}
// toastLog(title);
// sleep(1000*2);
// toastLog(desc);
// sleep(1000*2);
item.idx = indexInParent;
item.title = title;
item.desc = desc;
}else if(cell && cell.childCount() > 1){
cell = cell.child(1);//20
let title = cell.child(0).text();//21
let desc = cell.child(1).text();//21
// toastLog(title);
// sleep(1000*2);
// toastLog(desc);
// sleep(1000*2);
item.idx = indexInParent;
item.title = title;
item.desc = desc;
}else{
// toastLog(cell);
}
}
//往数组里面添加索引结果
if(item.idx != 0){
if(saveArray.length > 0){
if(item.idx > saveArray[saveArray.length - 1].idx){
saveArray.push(item);
}
}else{
saveArray.push(item);
}
}
}
}
//滑动搜索结果
function swapSearchResult(){
scrollDown();
}
function searchForKey(tkey){
sleep(1000*1.5);
//设置输入框里面的文字
id('m7').findOne().setText(tkey);
//点击键盘上面的'搜索'按钮
click(device.width - 8, device.height - 8);
var saveArray = [];
var rounds = 200;
for(var i=0;i