├── .build
├── default.init.aardio
├── default.main.aardio
└── default.Manifest.xml
├── dist
├── download
│ └── bm8zbu.mp4.dow!oad
└── WechatVideoSniffer.exe
├── res
├── BCMakeCert.dll
├── CertMaker.dll
├── FiddlerCore4.dll
└── BasicFormatsForCore.dll
├── README.assets
└── screenshots.gif
├── README.md
├── lib
└── config.aardio
├── default.aproj
└── main.aardio
/.build/default.init.aardio:
--------------------------------------------------------------------------------
1 | //发布前触发
2 | import ide;
--------------------------------------------------------------------------------
/dist/download/bm8zbu.mp4.dow!oad:
--------------------------------------------------------------------------------
1 | {
2 | acceptRanges="bytes";
3 | contentLength=26295001
4 | }
--------------------------------------------------------------------------------
/res/BCMakeCert.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuncv/WechatVideoSniffer/HEAD/res/BCMakeCert.dll
--------------------------------------------------------------------------------
/res/CertMaker.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuncv/WechatVideoSniffer/HEAD/res/CertMaker.dll
--------------------------------------------------------------------------------
/res/FiddlerCore4.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuncv/WechatVideoSniffer/HEAD/res/FiddlerCore4.dll
--------------------------------------------------------------------------------
/README.assets/screenshots.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuncv/WechatVideoSniffer/HEAD/README.assets/screenshots.gif
--------------------------------------------------------------------------------
/dist/WechatVideoSniffer.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuncv/WechatVideoSniffer/HEAD/dist/WechatVideoSniffer.exe
--------------------------------------------------------------------------------
/res/BasicFormatsForCore.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuncv/WechatVideoSniffer/HEAD/res/BasicFormatsForCore.dll
--------------------------------------------------------------------------------
/.build/default.main.aardio:
--------------------------------------------------------------------------------
1 | //此触发器在生成EXE以后执行
2 | import ide;
3 | import fsys;
4 |
5 | //获取生成的EXE文件路径
6 | var publishFile = ide.getPublishPath();
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WechatVideoSniffer
2 | 微信视频号PC版视频地址嗅探器
3 |
4 | 本项目采用[aardio](https://www.aardio.com/)编程语言开发
5 |
6 | ### 重要提醒
7 | 目前初步分析微信视频对流媒体进行加密,尚无逆向方法,可采用如下方法绕过:
8 | ~~1. 视频转发至`文件传输助手`,然后关闭微信视频窗口~~
9 | ~~2. 从`文件传输助手`打开视频,即可抓到未加密的视频地址~~
10 | pc端微信,搜一搜,在搜索列表播放的视频可以监听到进行下载
11 |
12 | ## 原理
13 |
14 | 使用FiddlerCore .Net组件,注册系统代理,监听主机的http/https请求,从而匹配出微信视频号视频的地址
15 |
16 | ## 使用方法
17 |
18 | 1. 打开软件,点击`监听`按钮
19 |
20 | > 如果第一次运行,会安装一个证书,这个证书的作用是建立中间人捕获https协议
21 |
22 | 2. 在`PC微信`上打开视频
23 |
24 | 3. 此时软件列表会更新视频链接,点击`下载选中` 按钮就可以下载视频,视频存放在`download`目录下。
25 |
26 | 
27 |
28 | ## 软件获取
29 |
30 | 自行编译或工程`dist`目录下载
31 |
--------------------------------------------------------------------------------
/lib/config.aardio:
--------------------------------------------------------------------------------
1 | //config 配置文件
2 | import fsys.config;
3 | config = fsys.config("/config/");
4 | //config = fsys.config( io.appData("/软件作者/应用程序名/") );
5 |
6 | //不需要序列化的配置名字前请添加下划线
7 | namespace config {
8 | __appName = "应用程序名";
9 | __website = "http://www.aardio.com/";
10 | }
11 |
12 | /**intellisense(config)
13 | __appName = 应用程序名
14 | __website = 官方网站
15 | saveAll() = 写入所有配置到文件
16 | ? = 获取值时指定不以下划线开始的配置表名称,\n返回一个可自动序列化到同名配置文件的表对象。\n如果此对象名以下划线开始,则可以正常读写值不会序列化为配置文件。\n否则不能对此对象直接赋值,只能对配置表对象的成员赋值。\n\n配置表可自动自文件加载,退出线程前自动序列化并存入文件。\n仅序列化以字符串、数值为键的元素,\n仅序列化值为字符串、数值、buffer 以及定义了 _serialize 元方法的成员。\n循环引用的值转换为 null,序列化时忽略成员函数\n!fsys_table.
17 | end intellisense**/
--------------------------------------------------------------------------------
/default.aproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.build/default.Manifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
10 | WechatVideoSniffer
11 |
12 |
13 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
52 |
53 |
54 |
55 |
56 |
57 | True/PM
58 | PerMonitorV2, PerMonitor
59 |
60 |
61 |
--------------------------------------------------------------------------------
/main.aardio:
--------------------------------------------------------------------------------
1 | import win.ui;
2 | /*DSG{{*/
3 | mainForm = win.form(text="WechatVideoSniffer";right=959;bottom=591)
4 | mainForm.add(
5 | btnClear={cls="button";text="清空列表";left=797;top=540;right=889;bottom=580;z=5};
6 | btnCopyUrl={cls="button";text="复制链接";left=797;top=177;right=889;bottom=211;z=6};
7 | btnDown={cls="button";text="下载选中";left=794;top=120;right=885;bottom=157;z=4};
8 | btnSniffer={cls="button";text="监听";left=794;top=14;right=885;bottom=51;z=1};
9 | btnStop={cls="button";text="停止";left=794;top=70;right=885;bottom=107;z=2};
10 | listview={cls="listview";left=17;top=15;right=787;bottom=584;edge=1;hscroll=1;z=3}
11 | )
12 | /*}}*/
13 |
14 | import dotNet
15 | import win.clip
16 | mainForm.listview.insertColumn( "URL",-1 )
17 | dotNet.reference({
18 | "FiddlerCore4" = $"res\FiddlerCore4.dll";
19 | "CertMaker" = $"res\CertMaker.dll";
20 | "BCMakeCert" = $"res\BCMakeCert.dll";
21 | "BasicFormatsForCore" = $"res\BasicFormatsForCore.dll"
22 | })
23 |
24 | var FiddlerCore4 = dotNet.load("FiddlerCore4")
25 | Fiddler = FiddlerCore4.import("Fiddler")
26 |
27 | InstallCertificate = function(){
28 | if(!Fiddler.CertMaker.rootCertExists()){
29 | if(!Fiddler.CertMaker.createRootCert()){
30 | return false;
31 | }
32 | if(Fiddler.CertMaker.trustRootCert()){
33 | return false;
34 | }
35 | }
36 | return true;
37 | }
38 |
39 | UninstallCertificate = function(){
40 | if(Fiddler.CertMaker.rootCertExists()){
41 | if(!Fiddler.CertMaker.removeFiddlerGeneratedCerts(true)){
42 | return false;
43 | }
44 | }
45 | return true;
46 | }
47 |
48 | // 视频链接过滤规则
49 | var urls = {}
50 | filterUrl = function(url){
51 | if(string.find(url,"^https\:\/\/finder*\.video\.qq\.com\/251\/20302\/") or string.find(url,"mpvideo\.qpic\.cn") ){
52 | // 去除无用链接格式
53 | if(!!string.match(url,"token=\w+")){
54 | if(!urls[url]){
55 | urls[url] = true
56 | return true;
57 | }
58 | }
59 | }
60 | return false;
61 | }
62 |
63 |
64 | AttachListening = function(){
65 | Fiddler.FiddlerApplication.BeforeRequest = function(s){
66 | s.bBufferResponse = false;
67 | if(filterUrl(s.fullUrl)){
68 | mainForm.listview.addItem( {s.fullUrl} )
69 | }
70 | }
71 | /*
72 | Fiddler.FiddlerApplication.BeforeResponse = function(s){
73 | if(string.startWith(s.fullUrl,"https://finder.video.qq.com")){
74 | mainForm.listview.addItem( {s.fullUrl} )
75 | }
76 | }
77 | */
78 | }
79 |
80 | StartupFiddlerCore = function(){
81 | Fiddler.FiddlerApplication.Startup(9898,Fiddler.FiddlerCoreStartupFlags.Default | Fiddler.FiddlerCoreStartupFlags.RegisterAsSystemProxy | Fiddler.FiddlerCoreStartupFlags.AllowRemoteClients)
82 | }
83 |
84 | UninstallFiddler = function(){
85 | if(Fiddler.FiddlerApplication.IsStarted()){
86 | Fiddler.FiddlerApplication.Shutdown();
87 | }
88 | }
89 |
90 | mainForm.btnSniffer.oncommand = function(id,event){
91 | InstallCertificate()
92 | AttachListening()
93 | StartupFiddlerCore()
94 | mainForm.btnSniffer.disabled = true
95 | }
96 |
97 | mainForm.btnStop.oncommand = function(id,event){
98 | UninstallCertificate()
99 | UninstallFiddler()
100 | mainForm.btnSniffer.disabled = false
101 | }
102 |
103 | mainForm.btnClear.oncommand = function(id,event){
104 | mainForm.listview.clear()
105 | urls = {}
106 | }
107 |
108 | mainForm.btnDown.oncommand = function(id,event){
109 | var index = mainForm.listview.selIndex
110 | if(index>0){
111 | var url = mainForm.listview.getItemText(index,1,10240)
112 | mainForm.btnDown.text = "下载中"
113 | mainForm.btnDown.disabled = true
114 | thread.invokeAndWait(
115 | function(url){
116 | import inet.httpFile
117 | math.randomize()
118 | var remoteFile = inet.httpFile( url,"/download/" + string.random(6) + ".mp4" )
119 | remoteFile.test()
120 | remoteFile.download()
121 | remoteFile.close()
122 | },url
123 | )
124 | mainForm.msgbox("下载完成")
125 | mainForm.btnDown.text = "下载选中"
126 | mainForm.btnDown.disabled = false
127 | }
128 | }
129 |
130 | mainForm.onClose = function(hwnd,message,wParam,lParam){
131 | //UninstallCertificate()
132 | UninstallFiddler()
133 | }
134 |
135 | mainForm.btnCopyUrl.oncommand = function(id,event){
136 | var index = mainForm.listview.selIndex
137 | if(index>0){
138 | var url = mainForm.listview.getItemText(index,1,10240)
139 | win.clip.write(url)
140 | }
141 | }
142 |
143 | mainForm.show();
144 | return win.loopMessage();
--------------------------------------------------------------------------------