Showing preview only (883K chars total). Download the full file or copy to clipboard to get everything.
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
================================================
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TestRunnerService">
<option name="projectConfiguration" value="pytest" />
<option name="PROJECT_TEST_RUNNER" value="pytest" />
</component>
</module>
================================================
FILE: .idea/inspectionProfiles/profiles_settings.xml
================================================
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
================================================
FILE: .idea/misc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7" project-jdk-type="Python SDK" />
</project>
================================================
FILE: .idea/modules.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/crawler-guide-code.iml" filepath="$PROJECT_DIR$/.idea/crawler-guide-code.iml" />
</modules>
</component>
</project>
================================================
FILE: .idea/vcs.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
================================================
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.c
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
SYMBOL INDEX (368 symbols across 73 files)
FILE: 第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.2 抖音protobuf解析案例/js.py
function on_message (line 5) | def on_message(data):
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast.js
method 'StringLiteral|NumericLiteral' (line 12) | 'StringLiteral|NumericLiteral'(path) {
method 'UnaryExpression' (line 18) | 'UnaryExpression'(path) {
method MemberExpression (line 36) | MemberExpression(path) {
method VariableDeclarator (line 47) | VariableDeclarator(path) {
method CallExpression (line 61) | CallExpression(path)
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/while-if转变为while-switch.js
method "WhileStatement" (line 36) | "WhileStatement"(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/三目运算符.js
method ConditionalExpression (line 17) | ConditionalExpression(path){
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/函数调用处自动替换计算值.js
method FunctionDeclaration (line 20) | FunctionDeclaration(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除多余的空行和空语句.js
method EmptyStatement (line 18) | EmptyStatement(path)
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除未被使用的变量.js
method VariableDeclarator (line 18) | VariableDeclarator(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除未被调用的函数.js
method FunctionDeclaration (line 25) | FunctionDeclaration(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/去控制流(for-switch).js
method ForStatement (line 49) | ForStatement(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/去控制流(while-switch).js
method WhileStatement (line 44) | WhileStatement(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/合并定义在object对象外面的key、value.js
method VariableDeclarator (line 22) | VariableDeclarator(path)
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理eval函数.js
method CallExpression (line 14) | CallExpression(path)
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理条件已知的if语句.js
method BinaryExpression (line 27) | BinaryExpression(path) {
method IfStatement (line 40) | IfStatement(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理条件已知的三元表达式.js
method ConditionalExpression (line 14) | ConditionalExpression(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理没有实参的自执行函数.js
method UnaryExpression (line 16) | UnaryExpression(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/对同一节点使用多个方法.js
function reduce_call_express (line 23) | function reduce_call_express(path) {
function delete_empty_params (line 26) | function delete_empty_params(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/条件表达式拆分为if语句.js
method ConditionalExpression (line 19) | ConditionalExpression(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/构造节点.js
method VariableDeclarator (line 19) | VariableDeclarator(path){
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/节点类型转换.js
method "VariableDeclarator" (line 17) | "VariableDeclarator"(path)
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原Array对象.js
method VariableDeclarator (line 26) | VariableDeclarator(path){
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原object对象.js
method VariableDeclarator (line 30) | VariableDeclarator(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原定义的字面量.js
method "Identifier" (line 19) | "Identifier"(path)
method VariableDeclarator (line 26) | VariableDeclarator(path)
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原成中文字符.js
method StringLiteral (line 17) | StringLiteral(path)
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原自执行函数的实参.js
method CallExpression (line 18) | CallExpression(path){
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/逗号表达式.js
method exit (line 27) | exit(path){
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/for_swith.js
method ForStatement (line 3) | ForStatement(path) {
FILE: 第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/lx.js
function test (line 1) | function test() {
FILE: 第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/webpack-export.js
function o (line 4) | function o(n){
FILE: 第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例一.js
function i (line 16) | function i(t) {
function r (line 91) | function r(t) {
function r (line 278) | function r(t) {
function i (line 285) | function i(t) {
function o (line 292) | function o(t) {
function e (line 325) | function e(e) {
function c (line 404) | function c(t) {
function n (line 407) | function n(t, e) {
function u (line 410) | function u(t, e) {
function r (line 413) | function r(t, e) {
function i (line 416) | function i(t, e) {
function o (line 419) | function o(t) {
function s (line 434) | function s(t) {
function l (line 441) | function l(t) {
function h (line 452) | function h(t) {
function t (line 570) | function t(t) {
function T (line 613) | function T(t, e) {
function n (line 618) | function n(t, e) {
function l (line 766) | function l(t, e, n, r, i) {
function t (line 993) | function t(t) {
function b (line 1016) | function b(t, e, n) {
function t (line 1863) | function t() {}
function t (line 1882) | function t(t) {
function t (line 1909) | function t(t) {
function t (line 1960) | function t(t) {
function P (line 2005) | function P() {
function j (line 2008) | function j(t, e) {
function V (line 2065) | function V(t, e) {
function q (line 2069) | function q(t) {
function U (line 2074) | function U(t) {
function t (line 2091) | function t() {
function Q (line 2144) | function Q() {
function t (line 2158) | function t() {}
function t (line 2167) | function t() {
function r (line 3078) | function r(t) {
function n (line 3084) | function n() {
function t (line 3229) | function t(t) {
function t (line 3322) | function t(t) {
function o (line 3327) | function o(t, e) {
function s (line 3330) | function s(t, e) {
function a (line 3335) | function a(t, e) {
function e (line 3347) | function e(t, e) {
function s (line 3804) | function s(t) {
function c (line 3809) | function c(s) {
function n (line 4112) | function n(t) {
function a (line 4130) | function a(t) {
function s (line 4159) | function s(t) {
function a (line 4162) | function a(t) {
function c (line 4165) | function c(t) {
function u (line 4168) | function u(t, e) {
function t (line 4222) | function t(t, e) {
function t (line 4231) | function t(t, e) {
function c (line 4271) | function c(t) {
function a (line 4320) | function a(t) {
function i (line 4353) | function i() {
function u (line 4384) | function u(t) {
function o (line 4419) | function o() {
function s (line 4422) | function s() {
function a (line 4425) | function a(e) {
function f (line 4454) | function f() {
function d (line 4459) | function d() {
function p (line 4490) | function p(t, e) {
function g (line 4494) | function g() {}
function i (line 4567) | function i(t, e) {
function i (line 4627) | function i(t) {
function r (line 4687) | function r(t) {
function get_passwrod (line 4701) | function get_passwrod(phone){
FILE: 第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例三.js
function a (line 122) | function a(i, n) {
function r (line 173) | function r() {
function o (line 211) | function o(n, r, e) {
function r (line 245) | function r(t) {
function m (line 369) | function m(t, i, n) {
function w (line 375) | function w(t, i, n) {
function g (line 381) | function g(t, i) {
function j (line 384) | function j(t, i) {
function r (line 391) | function r(t) {
function u (line 477) | function u(t, i, n, r) {
function d (line 523) | function d(t, i, n, r) {
function l (line 677) | function l(t, i, n, r) {
function s (line 692) | function s(t, i, n, r, e) {
function u (line 767) | function u(t, i, n, r, e, s, u) {
function e (line 915) | function e() {
function s (line 946) | function s(t, i, n, r, e, s) {
function e (line 986) | function e(t) {
function r (line 1035) | function r(t, i, n, r, e, s, u, o, h) {
function f (line 1080) | function f(t, i) {
function c (line 1087) | function c(t, i) {
function a (line 1092) | function a(t) {
function e (line 1267) | function e(t, i) {
function u (line 1368) | function u(t, i, n, r) {
function o (line 1378) | function o(t) {
function o (line 1449) | function o(t, i) {
function h (line 1452) | function h(t) {
function f (line 1457) | function f() {
function l (line 1477) | function l() {
function v (line 1515) | function v(t, i) {
function d (line 1518) | function d() {
function s (line 1673) | function s(t) {
function h (line 1696) | function h(t) {
function p (line 1701) | function p() {}
function h (line 1717) | function h(t, i) {
function f (line 1726) | function f(t) {
function c (line 1735) | function c(t, i) {
function a (line 1754) | function a(n, r) {
function c (line 1801) | function c(t, i) {
function r (line 1865) | function r(t, i, n) {
function u (line 1928) | function u(t, i) {
function e (line 1933) | function e(t) {
function w (line 2021) | function w(t, i) {
function r (line 2033) | function r(t) {
function r (line 2278) | function r(t, i) {
function e (line 2408) | function e(t, i) {
function e (line 2502) | function e(t, i, n) {
function s (line 2507) | function s(t) {
function f (line 2685) | function f(t, i) {
function c (line 2688) | function c(t, i, n, r) {
function h (line 2772) | function h(t, i, n) {
function f (line 2778) | function f() {}
function c (line 2779) | function c(t) {
function a (line 2785) | function a() {
function l (line 2791) | function l() {
function v (line 2802) | function v(t, i, n) {
function d (line 2805) | function d(t, i) {
function b (line 2810) | function b(t, i, n) {
function p (line 2820) | function p(t, i, n) {
function s (line 2959) | function s() {
function u (line 2962) | function u(t, i, n) {
function PolicyInfoByTypeIdParam_encode (line 3022) | function PolicyInfoByTypeIdParam_encode(m){
FILE: 第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例二.js
function reqId (line 1) | function reqId() {
function c (line 48) | function c(t, e) {
FILE: 第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.7 lsb隐写/lsb.py
function plus (line 3) | def plus(str):
function get_key (line 7) | def get_key(strr):
function mod (line 14) | def mod(x, y):
function func (line 17) | def func(old_img, str2, new_img):
FILE: 第三章:Web Js逆向/3.5 常见的编码和加密/3.5.6 AES/aes_encrypt.py
function add_to_16 (line 6) | def add_to_16(value):
function encrypt (line 12) | def encrypt(key, text):
function decrypt (line 19) | def decrypt(key, text):
FILE: 第三章:Web Js逆向/3.5 常见的编码和加密/3.5.7 RSA/rsa_encrypt.py
class RsaUtil (line 5) | class RsaUtil(object):
method __init__ (line 10) | def __init__(self,
method get_max_length (line 19) | def get_max_length(self, rsa_key, encrypt=True):
method encrypt_by_public_key (line 31) | def encrypt_by_public_key(self, message):
method decrypt_by_private_key (line 46) | def decrypt_by_private_key(self, message):
method sign_by_private_key (line 62) | def sign_by_private_key(self, data):
method verify_by_public_key (line 71) | def verify_by_public_key(self, message, signature):
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.2 newrank榜单逆向案例/js3.6.2.py
class XbRank (line 4) | class XbRank():
method __init__ (line 5) | def __init__(self):
method getxyz (line 22) | def getxyz(self,path):
method getMedia (line 179) | def getMedia(self,page=1):
method getRank1 (line 195) | def getRank1(self):
method getRank2 (line 216) | def getRank2(self):
method getRank3 (line 230) | def getRank3(self):
method getRank4 (line 239) | def getRank4(self):
method getRank5 (line 249) | def getRank5(self):
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.4 RSA参数加密逆向案例/js3.6.4.py
function encrypt_str (line 5) | def encrypt_str(data):
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.5 AES数据加密逆向案例/run.py
function decrypt (line 5) | def decrypt(info: str) -> list:
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.6 AES链接加密逆向案例/js3.6.6/test.js
function lx (line 3) | function lx(hh) {
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/run.py
function start (line 18) | def start():
function then (line 26) | def then():
function end (line 36) | def end(page=1):
function get_cookie_2 (line 42) | def get_cookie_2(data,hash):
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_md5.js
function hash (line 5) | function hash(_0x1502a6) {
function go (line 222) | function go(_0x3dcb2b) {
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_sha1.js
function hash (line 5) | function hash(_0x3cb311) {
function go (line 108) | function go(_0x3643f0) {
FILE: 第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_sha256.js
function hash (line 6) | function hash(_0xb3a2f3) {
function go (line 159) | function go(_0x50cd53) {
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t1.js
function get_signature (line 36) | function get_signature(url) {
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t2.js
function get_signature (line 48) | function get_signature(url) {
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t3.js
function ee (line 154) | function ee() {
function Vn (line 157) | function Vn(e, t) {
function a (line 179) | function a() {
function a (line 195) | function a() {
function Wn (line 207) | function Wn(e, t) {
function Vn (line 213) | function Vn(e, t) {
function Yn (line 261) | function Yn(e) {
function ew (line 284) | function ew() {
function a (line 291) | function a() {
function mu_ (line 461) | function mu_() {
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t4.js
function get_all (line 4) | function get_all(){
function make_all (line 159) | function make_all(){
function Cilame (line 357) | function Cilame(){
FILE: 第三章:Web Js逆向/3.7 浏览器环境补充/3.7.3 selenium环境模拟/test.py
function driver_sig (line 24) | def driver_sig(html_file):
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.1 微博登陆参数RPC/server.py
function check_permit (line 5) | async def check_permit(websocket):
function recv_msg (line 16) | async def recv_msg(websocket):
function main_logic (line 21) | async def main_logic(websocket, path):
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/server.py
function check_permit (line 4) | async def check_permit(websocket):
function recv_msg (line 9) | async def recv_msg(websocket):
function main_logic (line 14) | async def main_logic(websocket, path):
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index20231108.py
class Browser (line 5) | class Browser():
method __init__ (line 6) | def __init__(self, **kwargs, ):
method signature (line 57) | def signature(self, keyword, start_date, end_date):
method decrypt (line 103) | def decrypt(self,data):
method responseText (line 146) | def responseText(self, keyword, start_date, end_date):
method close (line 176) | def close(self):
function get_data (line 181) | def get_data(keyword, start_date, end_date):
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index_0.py
class Browser (line 31) | class Browser():
method __init__ (line 32) | def __init__(self, **kwargs, ):
method signature (line 76) | def signature(self, keyword, start_date, end_date):
method close (line 89) | def close(self):
function get_data (line 94) | def get_data(keyword, start_date, end_date):
function decrtptlx (line 107) | def decrtptlx(String):
FILE: 第三章:Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index_1.py
class Browser (line 29) | class Browser():
method __init__ (line 30) | def __init__(self, **kwargs, ):
method signature (line 74) | def signature(self, keyword, start_date, end_date):
method close (line 120) | def close(self):
function get_data (line 125) | def get_data(keyword, start_date, end_date):
function decrtptlx (line 135) | def decrtptlx(String):
FILE: 第九章:安卓逆向案例/9.1 某新闻加密参数分析和还原/frida1.py
function on_message (line 2) | def on_message(message, data):
FILE: 第九章:安卓逆向案例/9.2 某瓣签名Frida还原/frida1.py
function on_message (line 3) | def on_message(message, data):
FILE: 第九章:安卓逆向案例/9.2 某瓣签名Frida还原/run.py
function bd_request (line 7) | def bd_request():
function get_sig (line 24) | def get_sig(url,ts):
FILE: 第九章:安卓逆向案例/9.4 某图参数Frida+Flask RPC/run.py
function on_message (line 6) | def on_message(message, data):
function start_hook (line 10) | def start_hook():
function search (line 38) | def search():
FILE: 第九章:安卓逆向案例/9.6 某资讯加固脱壳和参数分析/hook.py
function on_message (line 2) | def on_message(message, data):
FILE: 第九章:安卓逆向案例/9.6 某资讯加固脱壳和参数分析/rpc.py
function on_message (line 4) | def on_message(message, data):
function start_hook (line 8) | def start_hook():
FILE: 第六章:安卓逆向/Frida/Frida自吐算法.js
function showStacks (line 7) | function showStacks() {
function stringToBase64 (line 33) | function stringToBase64(e) {
function base64ToString (line 57) | function base64ToString(e) {
function hexToBase64 (line 90) | function hexToBase64(str) {
function base64ToHex (line 93) | function base64ToHex(str) {
function hexToBytes (line 102) | function hexToBytes(str) {
function bytesToHex (line 118) | function bytesToHex(arr) {
function stringToHex (line 134) | function stringToHex(str) {
function stringToBytes (line 144) | function stringToBytes(str) {
function bytesToString (line 159) | function bytesToString(arr) {
function bytesToBase64 (line 167) | function bytesToBase64(e) {
function base64ToBytes (line 191) | function base64ToBytes(e) {
FILE: 第六章:安卓逆向/Frida/Frida自吐算法.py
function on_message (line 8) | def on_message(message, data):
function get_js (line 18) | def get_js():
function mians (line 647) | def mians(pakname):
FILE: 第六章:安卓逆向/Unidbg/xgorgon.java
class xgorgon (line 13) | public class xgorgon extends AbstractJni {
method createLibraryResolver (line 15) | private static LibraryResolver createLibraryResolver() {
method createARMEmulator (line 19) | private static AndroidEmulator createARMEmulator() {
method xgorgon (line 28) | private xgorgon() {
method destroy (line 40) | private void destroy() throws IOException {
method main (line 43) | public static void main(String[] args) throws Exception {
method xuzi1 (line 49) | public static String xuzi1(byte[] bArr) {
method test (line 63) | private void test() {
FILE: 第六章:安卓逆向/抖音/xposedhook.java
class AwemeSrv (line 39) | public class AwemeSrv extends NanoHTTPD {
method AwemeSrv (line 44) | public AwemeSrv() {
method init (line 48) | public void init(XC_LoadPackage.LoadPackageParam lpparam) {
method xuzi (line 57) | public static byte[] xuzi(String str) {
method xuzi1 (line 66) | public static String xuzi1(byte[] bArr) {
method get_leviathan (line 81) | public byte[] get_leviathan(int i,int time, byte[] s){
method parseStrToMd5L32 (line 86) | public static String parseStrToMd5L32(byte[] str){
method get_ttencrypt (line 106) | public byte[] get_ttencrypt(XC_LoadPackage.LoadPackageParam lpp2, byte...
method get_formdata (line 110) | public byte[] get_formdata(byte[] data) throws Exception{
method get_stub (line 119) | public String get_stub(byte[] barr) throws Exception{
method get_fed (line 125) | public String get_fed(String fed) throws Exception{
method get_device (line 129) | public String get_device(String url, String formdata) throws Exception {
method getUrl (line 154) | private static String getUrl(String url, String stub, long time1, Stri...
method serve (line 196) | public NanoHTTPD.Response serve(NanoHTTPD.IHTTPSession session) {
FILE: 第十一章:反爬虫补充/11.2 tls指纹识别/aiohttp_ja3.py
class DESAdapter (line 5) | class DESAdapter():
method __init__ (line 6) | def __init__(self):
method __call__ (line 9) | def __call__(self):
function main (line 19) | async def main():
FILE: 第十一章:反爬虫补充/11.2 tls指纹识别/requests_jar3.py
class DESAdapter (line 5) | class DESAdapter(HTTPAdapter):
method __init__ (line 6) | def __init__(self, *args, **kwargs):
method get_ciphers (line 10) | def get_ciphers(self):
method init_poolmanager (line 19) | def init_poolmanager(self, *args, **kwargs):
FILE: 第十一章:反爬虫补充/11.2 tls指纹识别/scrapy_Ja3_download.py
class SSLFactory (line 21) | class SSLFactory:
method __init__ (line 22) | def __init__(self):
method __call__ (line 25) | def __call__(self) -> ssl.SSLContext:
class Ja3DownloadHandler (line 38) | class Ja3DownloadHandler(HTTPDownloadHandler):
method __init__ (line 39) | def __init__(self, settings: Settings, crawler: Optional[Crawler] = No...
method _engine_started (line 46) | async def _engine_started(self, signal, sender):
method download_request (line 50) | def download_request(self, request: Request, spider: Spider) -> Deferred:
method _download_request (line 55) | async def _download_request(self, request: Request, spider: Spider) ->...
method close (line 77) | async def close(self):
FILE: 第十一章:反爬虫补充/11.3 http2/scrapy_http2_download.py
class HttpxDownloadHandler (line 17) | class HttpxDownloadHandler(HTTPDownloadHandler):
method __init__ (line 18) | def __init__(self, settings: Settings, crawler: Optional[Crawler] = No...
method _engine_started (line 24) | async def _engine_started(self, signal, sender):
method download_request (line 28) | def download_request(self, request: Request, spider: Spider) -> Deferred:
method _download_request (line 33) | async def _download_request(self, request: Request, spider: Spider) ->...
method close (line 53) | async def close(self):
FILE: 第十章:验证码识别技术/10.2.1.1 邮箱滑块验证码.py
class SlideCrack (line 10) | class SlideCrack(object):
method __init__ (line 11) | def __init__(self, gap, bg, out=None):
method clear_white (line 23) | def clear_white(img):
method template_match (line 47) | def template_match(self, tpl, target):
method image_edge_detection (line 66) | def image_edge_detection(img):
method discern (line 70) | def discern(self):
function get_distance (line 83) | def get_distance(gap, bg):
function main (line 97) | def main():
FILE: 第十章:验证码识别技术/10.2.1.2 邮箱滑块验证码.py
class SlideCrack (line 16) | class SlideCrack(object):
method __init__ (line 17) | def __init__(self, gap, bg, out=None):
method clear_white (line 29) | def clear_white(img):
method template_match (line 53) | def template_match(self, tpl, target):
method image_edge_detection (line 72) | def image_edge_detection(img):
method discern (line 76) | def discern(self):
function get_distance (line 89) | def get_distance(gap, bg):
function main (line 104) | def main():
FILE: 第十章:验证码识别技术/10.2.2 数美滑块验证码.py
function pad (line 22) | def pad(b):
function split_args (line 32) | def split_args(s):
function find_arg_names (line 51) | def find_arg_names(script):
function get_encrypt_content (line 84) | def get_encrypt_content(message, key, flag):
function get_random_ge (line 96) | def get_random_ge(distance):
function make_mouse_action_args (line 139) | def make_mouse_action_args(distance):
function get_distance (line 158) | def get_distance(fg, bg):
function update_protocol (line 169) | def update_protocol(protocol_num, js_uri):
function conf_captcha (line 182) | def conf_captcha(organization):
function register_captcha (line 204) | def register_captcha(organization):
function verify_captcha (line 228) | def verify_captcha(organization, rid, key, distance):
function get_verify (line 260) | def get_verify(organization):
function test (line 295) | def test():
FILE: 第四章:自动化工具的应用/4.2.4 Pyppeteer拦截器/test.py
function main (line 4) | async def main():
function intercept_request (line 16) | async def intercept_request(Request):
function intercept_response (line 31) | async def intercept_response(Response):
FILE: 第四章:自动化工具的应用/4.3.5 cefpython3爬虫实战/cefpython_demo.py
class ClientHandler (line 10) | class ClientHandler(object):
method __init__ (line 12) | def __init__(self, chromeObject):
method GetViewRect (line 15) | def GetViewRect(self, rect_out, **kwargs):
method OnConsoleMessage (line 21) | def OnConsoleMessage(self, browser, message, **kwargs):
method OnLoadError (line 25) | def OnLoadError(self, browser, frame, error_code, failed_url, **_):
method OnLoadingStateChange (line 31) | def OnLoadingStateChange(self, browser, is_loading, **kwargs):
class Client (line 44) | class Client(object):
method __init__ (line 45) | def __init__(self, width=1920, height=1080, headless=False):
method __getattr__ (line 65) | def __getattr__(self, name):
method getBrowser (line 69) | def getBrowser(self):
method LoadUrl (line 87) | def LoadUrl(self, url, synchronous=False):
method getSource (line 97) | def getSource(self, synchronous=False):
method Visit (line 110) | def Visit(self, value):
function BrowserThread (line 117) | def BrowserThread(browser):
FILE: 第四章:自动化工具的应用/4.7.3 autojs指数查询案例/main.js
function goToHomePage (line 5) | function goToHomePage(){
function goToSearchPage (line 24) | function goToSearchPage(){
function getSearchResult (line 36) | function getSearchResult(saveArray){
function swapSearchResult (line 101) | function swapSearchResult(){
function searchForKey (line 105) | function searchForKey(tkey){
function goToZhiShuPage (line 143) | function goToZhiShuPage(){
function getZhiShuForKey (line 159) | function getZhiShuForKey(tkey){
FILE: 第四章:自动化工具的应用/4.7.3 autojs指数查询案例/test.js
function goToHomePage (line 4) | function goToHomePage(){
function goToZhiShuPage (line 19) | function goToZhiShuPage(){
function getZhiShuForKey (line 35) | function getZhiShuForKey(tkey){
Condensed preview — 141 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (898K chars).
[
{
"path": ".idea/.gitignore",
"chars": 39,
"preview": "\n# Default ignored files\n/workspace.xml"
},
{
"path": ".idea/crawler-guide-code.iml",
"chars": 453,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"PYTHON_MODULE\" version=\"4\">\n <component name=\"NewModuleRootManager"
},
{
"path": ".idea/inspectionProfiles/profiles_settings.xml",
"chars": 174,
"preview": "<component name=\"InspectionProjectProfileManager\">\n <settings>\n <option name=\"USE_PROJECT_PROFILE\" value=\"false\" />\n"
},
{
"path": ".idea/misc.xml",
"chars": 288,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"JavaScriptSettings\">\n <option name=\"l"
},
{
"path": ".idea/modules.xml",
"chars": 288,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"ProjectModuleManager\">\n <modules>\n "
},
{
"path": ".idea/vcs.xml",
"chars": 180,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"VcsDirectoryMappings\">\n <mapping dire"
},
{
"path": "readme.md",
"chars": 4255,
"preview": "\n# 《爬虫逆向进阶实战》书籍代码库 (视频教程背面扫码!)\n\n书籍内容介绍:http://t.csdn.cn/Y1wsV (视频教程在书背面扫码!)\n\n官方旗舰店:https://item.jd.com/10050499209765"
},
{
"path": "update.txt",
"chars": 506,
"preview": "\n## Unable to access ... 443: Timed out\n\n## OpenSSL SSL_connect: Connection was reset in connection to github.com:443\n"
},
{
"path": "第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/js3.10.2.1.py",
"chars": 933,
"preview": "{\n \"currentPage\": 1,\n \"pageSize\": 20,\n \"searchFilter\": [0],\n \"searchScope\": 0,\n \"searchSort\": None,\n \""
},
{
"path": "第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/parent_sample.py",
"chars": 1661,
"preview": "# -*- coding: utf-8 -*-\n# @Author : lx\n\n# 专利详情页解析示例\n\nimport requests\nimport s_parent_pb2 as pb\nfrom lxpy import copy_he"
},
{
"path": "第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/s.proto",
"chars": 451,
"preview": "syntax = \"proto3\";\n\nmessage SearchService {\n enum SearchScope {\n A = 0;\n }\n enum SearchFilter {\n "
},
{
"path": "第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/s_parent_pb2.py",
"chars": 6297,
"preview": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler. DO NOT EDIT!\n# source: s_parent.proto\n\nfrom google"
},
{
"path": "第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.1 万方protobuf请求案例/s_pb2.py",
"chars": 8340,
"preview": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler. DO NOT EDIT!\n# source: s.proto\n\nfrom google.protob"
},
{
"path": "第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.2 抖音protobuf解析案例/js.py",
"chars": 963,
"preview": "from google.protobuf.json_format import MessageToDict\nfrom s_pb2 import *\nimport base64\n\ndef on_message(data):\n danmu"
},
{
"path": "第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.2 抖音protobuf解析案例/s.proto",
"chars": 1831,
"preview": "syntax = \"proto3\";\n\nmessage test{\n repeated Message message =1;\n string cursor =2;\n uint64 fetchInterval=3;\n "
},
{
"path": "第三章:Web Js逆向/3.10 常见协议分析/3.10.2 protobuf协议/3.10.2.2 抖音protobuf解析案例/s_pb2.py",
"chars": 37307,
"preview": "# -*- coding: utf-8 -*-\n# Generated by the protocol buffer compiler. DO NOT EDIT!\n# source: s.proto\n\nfrom google.protob"
},
{
"path": "第三章:Web Js逆向/3.11 常见反调试/内存爆破.md",
"chars": 2212,
"preview": "# 内存爆破\n\n在使用浏览器控制台(如 Chrome DevTools)或本地环境 调试 JavaScript 代码时,有时会遇到“内存爆破”(Memory Spike 或 Out of Memory)的问题。这通常发生在执行大量数据操作、"
},
{
"path": "第三章:Web Js逆向/3.11 常见反调试/开发者工具检测.md",
"chars": 853,
"preview": "# 开发者工具检测\n\n浏览器按 F12 后打开的工具,正式名称是 **开发者工具(Developer Tools,简称 DevTools)**,也常被称作「调试工具」「F12 工具」。\n\n检测原理可以参考 \"开发者工具检测器\":[https"
},
{
"path": "第三章:Web Js逆向/3.11 常见反调试/无限debugger.md",
"chars": 3226,
"preview": "# 无限debugger\n\n`debugger` 是JavaScript中的一个关键字,用于在代码中设置断点。当浏览器的开发者工具开启时,遇到 `debugger` 语句会暂停代码执行,等待用户操作。\n\n**无限** `**debugger"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast.js",
"chars": 2468,
"preview": "const parser = require(\"@babel/parser\");\nconst template = require(\"@babel/template\").default;\nconst traverse = require(\""
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/readme.md",
"chars": 40,
"preview": "补充部分的内容收集于网络,内容并未出现在书籍中,如有侵权请联系作者进行删除。\n\n"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/while-if转变为while-switch.js",
"chars": 2920,
"preview": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/三目运算符.js",
"chars": 1194,
"preview": "/*\ndesc : 把 a = m?11:22; 转成 m ? a = 11 : a = 22;\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/函数调用处自动替换计算值.js",
"chars": 2133,
"preview": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").d"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除多余的空行和空语句.js",
"chars": 526,
"preview": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除所有的代码注释.js",
"chars": 692,
"preview": "\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").defaul"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除未被使用的变量.js",
"chars": 880,
"preview": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/删除未被调用的函数.js",
"chars": 963,
"preview": "const fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/去控制流(for-switch).js",
"chars": 3762,
"preview": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/去控制流(while-switch).js",
"chars": 3112,
"preview": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/合并定义在object对象外面的key、value.js",
"chars": 1578,
"preview": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理eval函数.js",
"chars": 741,
"preview": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理条件已知的if语句.js",
"chars": 2098,
"preview": "const fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理条件已知的三元表达式.js",
"chars": 752,
"preview": "const fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default;"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/处理没有实参的自执行函数.js",
"chars": 752,
"preview": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/对同一节点使用多个方法.js",
"chars": 775,
"preview": "\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").default"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/条件表达式拆分为if语句.js",
"chars": 1271,
"preview": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").d"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/构造节点.js",
"chars": 1128,
"preview": "/*\n* 将 var a; 转换为 var a = 123 + 456;\n*\n* */\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst t"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/节点类型转换.js",
"chars": 1216,
"preview": "/*\ndesc : 将 BinaryExpression 类型转换为 CallExpression 类型\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/pa"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原Array对象.js",
"chars": 1942,
"preview": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").d"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原object对象.js",
"chars": 4080,
"preview": "/*\ndate : 2020/8/11\ndesc : \n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原定义的字面量.js",
"chars": 1163,
"preview": "/*\ndate : 2020/8/11\ndesc : \n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原成中文字符.js",
"chars": 640,
"preview": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").d"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/还原自执行函数的实参.js",
"chars": 1493,
"preview": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").d"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/ast补充/逗号表达式.js",
"chars": 1619,
"preview": "/*\n*/\n\nconst fs = require('fs');\nconst {parse} = require(\"@babel/parser\");\nconst traverse = require(\"@babel/traverse\").d"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/for_swith.js",
"chars": 2472,
"preview": "const visitor =\n {\n ForStatement(path) {\n const { init, update, test, body } = path.node;\n "
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/3.13.4 用AST还原代码/lx.js",
"chars": 598,
"preview": "function test() {\n for (var index = 0; index != 5;) {\n switch (index) {\n case 0:\n console.log(\"This is c"
},
{
"path": "第三章:Web Js逆向/3.13 反混淆AST/readme.md",
"chars": 2421,
"preview": "可能大家对ast不太理解,其实是通过生成语法树(AST),可快速修改代码中的一些混淆处理,从而简化代码,便于后续分析。\n\n比如通过Python来把JS转为AST并进行简单的操作,内容很简单。\n\n\n\n比如我们下图中的JS代码,有sum和min"
},
{
"path": "第三章:Web Js逆向/3.3 加密参数定位方法/3.3.7 注入和Hook/readme.md",
"chars": 6265,
"preview": "参数定位工具的下载地址在代码库中。\n\n下载地址:https://pan.baidu.com/s/1OmMiE4rJrTNwarw3EJbz0A?pwd=thyl\n\n---\n\n下面是一些常用的Js Hook代码。\n\n## Hook setIn"
},
{
"path": "第三章:Web Js逆向/3.3 加密参数定位方法/readme.md",
"chars": 3405,
"preview": "目前主流的定位方法如下\n\n## 全局搜索\n适用于:参数名是固定字符串(如`sign`、`token`、`timestamp`、`nonce`),且未被混淆的场景。\n\n**操作步骤**:\n\n1. 打开浏览器开发者工具(F12)→ 切换到`S"
},
{
"path": "第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/readme.md",
"chars": 118,
"preview": "新增webpack逆向的案例\n\n案例地址:https://space.bilibili.com/390499740\n\n\n可以用于webpack解包,代码格式化、反混淆的在线站点\nhttps://webcrack.netlify.app/"
},
{
"path": "第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/webpack-export.js",
"chars": 419,
"preview": "var lx;\n!function (e){\n var report = {};\n function o(n){\n if (report[n])\n return report[n].expor"
},
{
"path": "第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例一.js",
"chars": 201979,
"preview": "// 贝壳网登录的webpack逆向案例\nwindow = {}\nwindow.location = {\n href:'https://zz.ke.com/?utm_source=baidu&utm_medium=pinzhuan&u"
},
{
"path": "第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例三.js",
"chars": 124578,
"preview": "/*!\n爬虫逆向进阶实战-JS逆向3.4.1 webpack案例三\n视频地址:https://www.bilibili.com/video/bv1MB4y1h7nK\n */\nvar aaa;\n!function(g) {\n \"use "
},
{
"path": "第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.1 webpack导出/案例二.js",
"chars": 3142,
"preview": " function reqId() {\n var t = {};\n var e = undefined;\n var n = undefined;\n var r = [123, 48, "
},
{
"path": "第三章:Web Js逆向/3.4 常见的压缩和混淆/3.4.7 lsb隐写/lsb.py",
"chars": 1553,
"preview": "from PIL import Image\n\ndef plus(str):\n # 返回指定长度的字符串,原字符串右对齐,前面填充0。\n return str.zfill(8)\n\ndef get_key(strr):\n st"
},
{
"path": "第三章:Web Js逆向/3.5 常见的编码和加密/3.5.6 AES/aes_encrypt.js",
"chars": 472,
"preview": "let password = \"lx123\";\nlet key = \"1234567890abcdef\"\n// AES加密\ncfg = {\n mode: CryptoJs.mode.ECB,\n padding: CryptoJs.pad.P"
},
{
"path": "第三章:Web Js逆向/3.5 常见的编码和加密/3.5.6 AES/aes_encrypt.py",
"chars": 743,
"preview": "import base64\nfrom Crypto.Cipher import AES\n\n# AES\n# 需要补位,str不是16的倍数那就补足为16的倍数\ndef add_to_16(value):\n while len(value"
},
{
"path": "第三章:Web Js逆向/3.5 常见的编码和加密/3.5.7 RSA/rsa_encrypt.js",
"chars": 263,
"preview": "window = global;\nconst JSEncrypt = require('jsencrypt');\npublickey = '公钥';\n\n// 加密\nlet jse = new JSEncrypt();\njse.setPubl"
},
{
"path": "第三章:Web Js逆向/3.5 常见的编码和加密/3.5.7 RSA/rsa_encrypt.py",
"chars": 2673,
"preview": "import base64\nimport rsa\nfrom rsa import common\n\nclass RsaUtil(object):\n PUBLIC_KEY_PATH = 'public_key.pem' # 公钥\n "
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.1 virustotal逆向入门案例/js3.6.1.py",
"chars": 1308,
"preview": "import execjs\nimport requests\nfrom lxpy import copy_headers_dict\n\nurl = 'https://www.virustotal.com/ui/search?limit=20&r"
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.2 newrank榜单逆向案例/js3.6.2.py",
"chars": 12712,
"preview": "import requests\nimport execjs\n\nclass XbRank():\n def __init__(self):\n self.session=requests.session()\n s"
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.3 MD5加密逆向案例/js3.6.3.py",
"chars": 54,
"preview": "from lxpy.encrypt import md5\n\nprint(md5.get_md5('11'))"
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.4 RSA参数加密逆向案例/js3.6.4.py",
"chars": 760,
"preview": "from Cryptodome.PublicKey import RSA\nfrom Cryptodome.Cipher import PKCS1_v1_5\nimport base64\n\ndef encrypt_str(data):\n "
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.5 AES数据加密逆向案例/run.py",
"chars": 575,
"preview": "import requests\nimport base64,json,re\nfrom Crypto.Cipher import AES\n\ndef decrypt(info: str) -> list:\n key = '3sd&d24h"
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.6 AES链接加密逆向案例/js3.6.6/js3.6.6.py",
"chars": 939,
"preview": "import execjs\n\njs = '''\n// npm install crypto-js\n\nvar CryptoJS = require(\"crypto-js\");\n\nfunction lx(hh) {\n var aa = h"
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.6 AES链接加密逆向案例/js3.6.6/package.json",
"chars": 54,
"preview": "{\n \"dependencies\": {\n \"crypto-js\": \"^4.1.1\"\n }\n}\n"
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.6 AES链接加密逆向案例/js3.6.6/test.js",
"chars": 859,
"preview": "var CryptoJS = require(\"crypto-js\");\n\nfunction lx(hh) {\n var aa = hh.split(\"/\");\n var aaa = aa.length;\n var bbb"
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/run.py",
"chars": 1576,
"preview": "# -*- coding: utf-8 -*-\n# @Time : 2021/12/8 10:58\n# @IDE :PyCharm\n\nimport requests\nimport re\nimport execjs\n\nheaders ="
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_md5.js",
"chars": 14605,
"preview": "window = {}\nwindow.navigator={\n'userAgent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Ge"
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_sha1.js",
"chars": 5249,
"preview": "window = {}\nwindow.navigator={\n'userAgent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Ge"
},
{
"path": "第三章:Web Js逆向/3.6 加密参数还原与模拟/3.6.7 cnvd加速乐分析案例/t_sha256.js",
"chars": 8071,
"preview": "window = {}\nwindow.navigator={\n'userAgent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Ge"
},
{
"path": "第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/js-hook.txt",
"chars": 1489,
"preview": "\n## Hook setInterval \n```js\nlet _setInterval=setInterval;\nsetInterval=function(a,b){\n\tif(a.toString().indexOf(\"debugger\""
},
{
"path": "第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/readme.md",
"chars": 2463,
"preview": "常被检测的环境中,有windows、location、navigate、document、native、canvas等。\n\n除了这些属性外,还有针对于自动化的检测、node环境的检测、以及浏览器指纹检测、TLS指纹校验等。\n\n所谓的补环境是"
},
{
"path": "第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t0 浏览器指纹解读.md",
"chars": 5668,
"preview": "科普文,简单解读浏览器指纹相关内容,如有描述不周望谅解。\n\n\n---\n\n## 浏览器指纹\n浏览器指纹很重要,在数据采集、搜索引擎、埋点分析、网站测试等方面都有体现。\n\n指纹通常是指服务端的为了做识别而收集的客户端设备信息。即使没有cooki"
},
{
"path": "第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t1.js",
"chars": 1023,
"preview": "// 最基础的\nvar glb;\nvar window = global;\nwindow.document = {referrer: \"\"};\nwindow.location = {\n hash: \"\",\n host: \"\",\n"
},
{
"path": "第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t2.js",
"chars": 1327,
"preview": "// jsdom\nconst jsdom = require(\"jsdom\");\nconst { JSDOM } = jsdom;\nconst dom = new JSDOM(`<!DOCTYPE html><p>Hello Lx</p>`"
},
{
"path": "第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t3.js",
"chars": 14483,
"preview": "var exports = undefined\n , module = undefined\n , Image = function Image() {}\n , PluginArray = function PluginArray() "
},
{
"path": "第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t4.js",
"chars": 70737,
"preview": "// 从浏览器直接扒各种参数环境的脚本,忘记当时转谁的了,请联系我增加署名\n\nconsole.log(make_all()) // 使用时候解开该行注释,然后将生成的代码都放到控制台中直接执行,复制生成的字符出即可。\nfunction ge"
},
{
"path": "第三章:Web Js逆向/3.7 浏览器环境补充/3.7.0 浏览器环境补充/t5补环境框架.md",
"chars": 732,
"preview": "# 补环境框架\n\n补环境框架可以帮助代码在接近原始环境的条件下执行,相当于前面模板的组合加强版。\n\n---\n\n\n## js-sandbox-env-framework\n\n[https://github.com/lasawang/js-san"
},
{
"path": "第三章:Web Js逆向/3.7 浏览器环境补充/3.7.3 selenium环境模拟/readme.md",
"chars": 6752,
"preview": "## 补不了就用浏览器\n\n补环境是指用于在**非浏览器环境**下模拟浏览器运行 JavaScript 的工具。但是实在补不出来也不能一直耗着浪费时间,那就不补了,直接用浏览器环境执行代码。\n\n常用方式 playwright+express"
},
{
"path": "第三章:Web Js逆向/3.7 浏览器环境补充/3.7.3 selenium环境模拟/test.py",
"chars": 1310,
"preview": "# -*- coding: utf-8 -*-\nimport os\nfrom selenium import webdriver\n\nua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...'\nPR"
},
{
"path": "第三章:Web Js逆向/3.7 浏览器环境补充/readme.md",
"chars": 2317,
"preview": "# 背景\n\n## 一、什么是“补环境”?\n\n在 JavaScript 逆向中,“补环境”指的是**在非浏览器环境中模拟或还原浏览器运行 JavaScript 所需的上下文环境**,以便能够让目标 JavaScript 脚本正常执行。\n\n简单"
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.0 加密方法远程调用/readme.md",
"chars": 240,
"preview": "加密方法的远程调用主要是使用了RPC协议,RPC(Remote Procedure Call)是远程调用的意思。RPC的应用十分广泛,比如在分布式中的进程间通讯、微服务中的节点通讯。\n\n我们这里使用的rpc其实是实现两个不同进程通信的一种方"
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.0 加密方法远程调用/头条系web-RPC.md",
"chars": 3782,
"preview": "以头条系某短视频(dy)web页面搜索为例,通过RPC的逻辑实现数据采集。\n\n目前方案通用于头条系web页面。因为其当前产品大都基于XMLHttpRequest的send方法做一些校验,我们可以自启一个浏览器去完成XMLHttpReques"
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.1 微博登陆参数RPC/client.js",
"chars": 401,
"preview": "!function(){\n if (window.flagLX){}\n else{\n window.weiboLx = makeRequest;\n var ws = new WebSocket(\"ws://127"
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.1 微博登陆参数RPC/server.py",
"chars": 663,
"preview": "import asyncio\nimport websockets\nimport time\n\nasync def check_permit(websocket):\n # 账号列表\n for send_text in [\n "
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/2022-05-25更新.md",
"chars": 2614,
"preview": "## update: 2022-05-25\n\n本文内容是继之前失效文章的补充。 RPC的方法大家应该都从书中掌握了。 (虽然官网更新了,但是没有掌握的还可以看一下视频)\n\n\n所以长话短说,本篇的内容是找新版本弹幕wss协议的RPC的入口"
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/client.js",
"chars": 1089,
"preview": "// 这是当前新版的\nwindow.dataLx = s.toObject();\n!function(){\n var res = window.dataLx;\n if (window.flagLX"
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/readme.md",
"chars": 82,
"preview": "\n1、更新内容在 2022-05-25更新.md 中\n\n2、更新的视频在 https://www.bilibili.com/video/BV1o34y1L7RX/\n"
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.2 抖音直播数据RPC/server.py",
"chars": 519,
"preview": "import asyncio\nimport websockets\n\nasync def check_permit(websocket):\n send_text = 'lx'\n await websocket.send(send_"
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index20231108.py",
"chars": 8113,
"preview": "import json\nfrom selenium import webdriver\n\n\nclass Browser():\n def __init__(self, **kwargs, ):\n self.debug = k"
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index_0.py",
"chars": 4977,
"preview": "# -*- coding: utf-8 -*-\n# @Time : 2021/9/27 14:46\n# @Author : lx\n\nfrom selenium import webdriver\nfrom lxpy import co"
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/juliang_index_1.py",
"chars": 6573,
"preview": "# -*- coding: utf-8 -*-\n\nimport json\nfrom selenium import webdriver\nfrom lxpy import copy_headers_dict\n\nh = copy_headers"
},
{
"path": "第三章:Web Js逆向/3.9 加密方法远程调用/3.9.3 巨量指数签名RPC/readme.md",
"chars": 563,
"preview": "(TODO:之前的版本失效了,大家查看最近提交的文件,旧版可作为参考)\n\n对RPC来讲,需要找可调用的方法入口,像头条系这种在send后重写url的,可以通过查找xmlhttprequest堆栈来定位。\n\n\n、夜神模拟器(安卓5)、Frida(12.11.18)、Unidbg(0.9.5)\n\n> 声明:文章内容仅供参考学习,如有侵权请"
},
{
"path": "第九章:安卓逆向案例/9.0 书外新增案例/飞瓜sign.md",
"chars": 4390,
"preview": "本文案例是飞瓜APP的Sign参数分析和生成。\n\n> 声明:文章内容仅供参考学习,如有侵权请联系作者进行删除。\n\n\n\n---\n\n## 接口分析\n\n观察后发现,同一时间请求的不同接口,Sign是相同的。\n:\n print(\"[%s] => %s\" % (message, data))\n\nsession = frida.get_usb_devi"
},
{
"path": "第九章:安卓逆向案例/9.2 某瓣签名Frida还原/frida1.py",
"chars": 1019,
"preview": "import frida, sys\n\ndef on_message(message, data):\n if message['type'] == 'send':\n print(\"[*] {0}\".format(messa"
},
{
"path": "第九章:安卓逆向案例/9.2 某瓣签名Frida还原/run.py",
"chars": 1069,
"preview": "import requests,time\nfrom urllib.parse import quote,urlparse\nimport hashlib,base64,hmac\n\nheaders = {\"User-Agent\": \"api-c"
},
{
"path": "第九章:安卓逆向案例/9.4 某图参数Frida+Flask RPC/run.py",
"chars": 1410,
"preview": "import frida\nfrom flask import Flask, jsonify, request\n\napp = Flask(__name__)\n\ndef on_message(message, data):\n print("
},
{
"path": "第九章:安卓逆向案例/9.5 某东加密参数Unidbg生成/readme.md",
"chars": 147,
"preview": "**案例 9.3也在其中**\n\n**lxServer**: 是书中对某东APP的sign参数分析和通过Unidbg模拟调用.\n\n**unidbg-jd-sign-11**:新增的,是对11版本的调用。\n\n\n- 运行前准备好java环境以及m"
},
{
"path": "第九章:安卓逆向案例/9.6 某资讯加固脱壳和参数分析/hook.py",
"chars": 931,
"preview": "import frida, sys\ndef on_message(message, data):\n print(\"[%s] => %s\" % (message, data))\n\nsession = frida.get_usb_devi"
},
{
"path": "第九章:安卓逆向案例/9.6 某资讯加固脱壳和参数分析/rpc.py",
"chars": 1425,
"preview": "import frida\n\n\ndef on_message(message, data):\n print(\"[%s] => %s\" % (message, data))\n\n\ndef start_hook():\n session "
},
{
"path": "第八章:抓包技巧汇总/heytap软件商店抓包.md",
"chars": 938,
"preview": "本文内容是 heytap软件商店抓包案例。\n\n---\n\n用常规的http/https工具,比如charles、fiddler去抓包时,无法正常对heytapmobi进行抓包。\n\n会提示客户端SSL握手失败,Received fatal al"
},
{
"path": "第八章:抓包技巧汇总/readme.md",
"chars": 66,
"preview": "对应第八章《八:抓包技巧汇总》\n\n大家先把书中概念性的东西了解一下\n\n书中出现的内容就不重复贴了,这里加一些案例和知识点,持续更新\n"
},
{
"path": "第八章:抓包技巧汇总/夜神安卓7导入charles证书.md",
"chars": 1305,
"preview": "夜神安卓7系统的charles证书导入。由于用户安装的外部证书不被信任,所以需要把SSL证书安装到安卓系统证书目录里。\n\n---\n\n## 一:下载证书\n开启本地代理,在浏览器输入 chls.pro/ssl 下载证书到本地。\n\n把证书原名ch"
},
{
"path": "第八章:抓包技巧汇总/快手app抓包.md",
"chars": 2377,
"preview": "# 快手app抓包\n\n快手app版本8+往后使用的quic协议。QUIC 基于 UDP 传输、多数代理工具不支持,且快手用 Aegon 库强制 QUIC、同时叠加证书校验与代理绕过机制,导致常规代理抓包失效。\n\n最常用的解决方法是将app的"
},
{
"path": "第八章:抓包技巧汇总/抖音app抓包.md",
"chars": 771,
"preview": "# 抖音app抓包\n\n核心逻辑:Hook 抖音网络库 libsscronet.so,修改 QUIC 配置使其降级为 HTTPS。\n\n```javascript\nJava.perform(function() {\n const Cron"
},
{
"path": "第八章:抓包技巧汇总/某物app抓包.md",
"chars": 2157,
"preview": "\n## 环境准备\n模拟器夜神安卓7版本。配合charles的抓包步骤:[http://t.csdn.cn/lpNaV](http://t.csdn.cn/lpNaV)\n\n模拟器需要是64位的,在商店下载推荐版本时会提示更新。\n\n|\n|adb shell\t|进入shell|\n|a"
},
{
"path": "第六章:安卓逆向/Frida/Frida自吐算法.js",
"chars": 21142,
"preview": "\n// 代码引用自 Mobile security 王铁头\n\nvar N_ENCRYPT_MODE = 1\nvar N_DECRYPT_MODE = 2\n\nfunction showStacks() {\n var Exception "
},
{
"path": "第六章:安卓逆向/Frida/Frida自吐算法.py",
"chars": 23784,
"preview": "# -*- coding: UTF-8 -*-\n# 代码引用自 guyezhou51\n\nimport frida\nimport sys\n\n\ndef on_message(message, data):\n if message['typ"
},
{
"path": "第六章:安卓逆向/Frida/Frida过Root检测.js",
"chars": 15793,
"preview": "\n// $ frida -l antiroot.js -U -f com.example.app --no-pause\n// CHANGELOG by Pichaya Morimoto (p.morimoto@sth.sh): \n// -"
},
{
"path": "第六章:安卓逆向/Unidbg/xgorgon.java",
"chars": 2815,
"preview": "package com.douyin;\nimport com.github.unidbg.*;\nimport com.github.unidbg.linux.android.AndroidARMEmulator;\nimport com.gi"
},
{
"path": "第六章:安卓逆向/常见检测及绕过/Frida检测的处理思路.md",
"chars": 156,
"preview": "执行顺序:\n\n 方法一:找开源方案(10分钟找不到就方法二)\n\n 方法二:换增强版的frida-server(失败到方法三)\n\n 方法三:对应用降级。 (失败到方法四)\n\n 方法四:hook dlopen找so,删除"
},
{
"path": "第六章:安卓逆向/常见检测及绕过/Root检测的处理示例-1.md",
"chars": 478,
"preview": "# Root检测的处理示例-1\n\n以**化妆品监管app**的root检测示例:\n\n安装**Magisk + Shamiko**,通过magiskHide配置加入隐藏列表的进程。\n\n1、在magisk右上角开启zygisk \n2、安装隐藏"
},
{
"path": "第六章:安卓逆向/常见检测及绕过/设备环境检测apk.md",
"chars": 847,
"preview": "# 环境检测apk(推荐)\n\n## Ruru.apk\n\n一款体积小巧、功能强大的手机检测软件,通过它用户只需动动手指便可以对手机各个模块运行状况进行检测操作,一旦发现相应的异常数据便会进行及时提醒操作。\n\n## RiskDetector.a"
},
{
"path": "第六章:安卓逆向/抖音/xposedhook.java",
"chars": 7770,
"preview": "package com.example.xuziqiang.nanotest;\n\nimport de.robv.android.xposed.XposedBridge;\nimport de.robv.android.xposed.Xpose"
},
{
"path": "第十一章:反爬虫补充/11.1 css动态字体反爬/选哪儿网动态字体.py",
"chars": 1242,
"preview": "# -*- coding: utf-8 -*-\n\nimport requests\nimport re\n\nheaders = {\n 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x6"
},
{
"path": "第十一章:反爬虫补充/11.2 tls指纹识别/aiohttp_ja3.py",
"chars": 949,
"preview": "import random\nimport ssl\n# aiohttp 修改 ja3\n\nclass DESAdapter():\n def __init__(self):\n self.ORIGIN_CIPHERS = ('E"
},
{
"path": "第十一章:反爬虫补充/11.2 tls指纹识别/requests_jar3.py",
"chars": 1108,
"preview": "from requests.adapters import HTTPAdapter\nfrom urllib3.util.ssl_ import create_urllib3_context\nimport random,requests\n\nc"
},
{
"path": "第十一章:反爬虫补充/11.2 tls指纹识别/scrapy_Ja3_download.py",
"chars": 3067,
"preview": "# -*- coding: utf-8 -*-\nfrom typing import Optional\nimport random\nimport ssl\nfrom twisted.internet.defer import Deferred"
},
{
"path": "第十一章:反爬虫补充/11.3 http2/scrapy_http2_download.py",
"chars": 2323,
"preview": "# -*- coding: utf-8 -*-\nfrom typing import Optional\n\nfrom twisted.internet.defer import Deferred\n\nfrom scrapy import sig"
},
{
"path": "第十章:验证码识别技术/10.2.1.1 邮箱滑块验证码.py",
"chars": 4206,
"preview": "from selenium import webdriver\nfrom io import BytesIO\nimport cv2,numpy as np, random, requests, time\nfrom selenium.webdr"
},
{
"path": "第十章:验证码识别技术/10.2.1.2 邮箱滑块验证码.py",
"chars": 4819,
"preview": "# -*- coding: utf-8 -*-\nimport re\nfrom selenium import webdriver\nimport cv2, numpy as np, random, requests, time\nfrom se"
},
{
"path": "第十章:验证码识别技术/10.2.2 数美滑块验证码.py",
"chars": 7184,
"preview": "\"\"\"\n数美滑块验证码验证\n\"\"\"\n\nimport base64\nimport json\nimport random\nimport re\nimport time\nfrom io import BytesIO\nimport cv2\nimpor"
},
{
"path": "第四章:自动化工具的应用/4.2.4 Pyppeteer拦截器/test.js",
"chars": 1559,
"preview": "var request = require('request');\nconst puppeteer = require(\"puppeteer-extra\");\nconst StealthPlugin = require(\"puppeteer"
},
{
"path": "第四章:自动化工具的应用/4.2.4 Pyppeteer拦截器/test.py",
"chars": 1045,
"preview": "import asyncio\nfrom pyppeteer import launch\n\nasync def main():\n browser = await launch()\n page = await browser.new"
},
{
"path": "第四章:自动化工具的应用/4.3.5 cefpython3爬虫实战/cefpython_demo.py",
"chars": 4305,
"preview": "import sys\nimport threading\nfrom cefpython3 import cefpython as cef\n\n# 代码转自 https://blog.csdn.net/jianshen_5465/article/"
},
{
"path": "第四章:自动化工具的应用/4.7.3 autojs指数查询案例/main.js",
"chars": 5347,
"preview": "// toast('Hello, Auto.js');\napp.launchApp('微信');\n\n//返回到首页\nfunction goToHomePage(){ \n let k = 0;\n while(k < 30){"
},
{
"path": "第四章:自动化工具的应用/4.7.3 autojs指数查询案例/test.js",
"chars": 1465,
"preview": "app.launchApp('微信');\n\n//跳转到首页\nfunction goToHomePage(){\n let k = 0;\n while(k < 30){\n k = k + 1;\n if(t"
},
{
"path": "附录(一些经验)/readme.md",
"chars": 84,
"preview": "我觉得附录才是对大家帮助最大的东西,可惜出版社开源节流,没有印在书中。\n\n因为这里面是我自身经验的总结,比如检索技巧和面试之谈。\n\n如果你看到了这里,一定不要错过!\n\n"
},
{
"path": "附录(一些经验)/关于AI逆向.md",
"chars": 1859,
"preview": "当AI从辅助工具升级为逆向执行者,以后可能无需人工编写代码、分析汇编,即可完成静态解析+动态调试+算法复现全流程。\n\n我们作为指挥者把控方向,要有不被AI误导的能力。\n\n\n# AI逆向JS-动态前瞻\n\n## Js-reverse-mcp\n\n"
},
{
"path": "附录(一些经验)/检索技巧.md",
"chars": 1203,
"preview": "## 爬虫工程师应该掌握的检索技巧\n\n一般来说我们要做的事情前人已经完成过,其实不需要自己动手去逆向,找到前人的代码合理更改能极大程度地提高工作效率,我分享一下互联网中的信息检索技巧。\n\n/面试之谈.md",
"chars": 852,
"preview": "## 总结了一些面试经验分享给大家\n\n其实我本身并没有换几次工作,但是参加的面试次数可以称得上是不胜枚举,因为只想找一个自己喜欢的工作环境和生活节奏,所以会给自己获取更多的选择。\n\n建议大家每年参与几次面试或者旁听他人面试,可以看一看最新的"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the lixi5338619/lxBook GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 141 files (788.1 KB), approximately 238.3k tokens, and a symbol index with 368 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.