diff --git a/.gitignore b/.gitignore
index 1a884eb..bd72ed2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,9 @@
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+FiddlerCore4
+
+
# User-specific files
*.rsuser
*.suo
diff --git a/BarrageGrab/Appsetting.cs b/BarrageGrab/Appsetting.cs
index 6b144c3..d114af1 100644
--- a/BarrageGrab/Appsetting.cs
+++ b/BarrageGrab/Appsetting.cs
@@ -11,12 +11,14 @@ namespace BarrageGrab
{
private static readonly Appsetting ins = new Appsetting();
+ public static Appsetting Instanse { get => Get(); }
public Appsetting()
{
FilterProcess = AppSettings["filterProcess"].Trim().Split(',');
WsProt = int.Parse(AppSettings["wsListenPort"]);
- PrintBarrage = AppSettings["printBarrage"] == "on";
+ PrintBarrage = AppSettings["printBarrage"].ToLower() == "true";
+ ProxyPort = int.Parse(AppSettings["proxPort"]);
}
public static Appsetting Get()
@@ -38,5 +40,10 @@ namespace BarrageGrab
/// 控制台打印消息开关
///
public bool PrintBarrage { get; private set; }
+
+ ///
+ /// 代理端口
+ ///
+ public int ProxyPort { get; private set; } = 8827;
}
}
diff --git a/BarrageGrab/JsonEntity/BarrageMessages.cs b/BarrageGrab/JsonEntity/BarrageMessages.cs
index e0005f8..484144b 100644
--- a/BarrageGrab/JsonEntity/BarrageMessages.cs
+++ b/BarrageGrab/JsonEntity/BarrageMessages.cs
@@ -132,7 +132,7 @@
///
/// 抖币价格
///
- public int GiamondCount { get; set; }
+ public int DiamondCount { get; set; }
}
///
diff --git a/BarrageGrab/Proxy/FiddlerProxy.cs b/BarrageGrab/Proxy/FiddlerProxy.cs
new file mode 100644
index 0000000..afadd4c
--- /dev/null
+++ b/BarrageGrab/Proxy/FiddlerProxy.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading.Tasks;
+using ColorConsole;
+using Fiddler;
+using Microsoft.Win32;
+
+namespace BarrageGrab.Proxy
+{
+ ///
+ /// FiddlerCore 代理程序
+ ///
+ [Obsolete("由于框架存在内存泄漏,已弃用,请使用TitaniumProxy)", false)]
+ internal class FiddlerProxy : SystemProxy
+ {
+ bool disposed = false;
+ ConsoleWriter console = new ConsoleWriter();
+
+ public FiddlerProxy()
+ {
+ InitFiddler();
+ }
+
+ //初始化Fiddler
+ private void InitFiddler()
+ {
+ //这个名字随便
+ FiddlerApplication.SetAppDisplayName("FiddlerCore");
+ FiddlerApplication.OnWebSocketMessage += FiddlerApplication_OnWebSocketMessage;
+ //FiddlerApplication.OnReadResponseBuffer += OnReadResponseBuffer;
+ //设置pac规则,匹配douyin且排除douyincdn的host走代理,其余的直连
+ FiddlerApplication.Prefs.SetStringPref("fiddler.proxy.pacfile.text", $"if (/douyin(?!cdn)/.test(host)) {{return 'PROXY 127.0.0.1:{base.ProxyPort}' }} return 'DIRECT'");
+
+
+ X509Certificate2 oRootCert;
+ if (null == CertMaker.GetRootCertificate())
+ {
+ CertMaker.createRootCert();
+ oRootCert = CertMaker.GetRootCertificate();
+ X509Store certStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
+ certStore.Open(OpenFlags.ReadWrite);
+ try
+ {
+ certStore.Add(oRootCert);
+ }
+ finally
+ {
+ certStore.Close();
+ }
+ }
+ else
+ {
+ oRootCert = CertMaker.GetRootCertificate();
+ }
+ //信任证书
+ CertMaker.trustRootCert();
+
+ FiddlerApplication.oDefaultClientCertificate = oRootCert;
+ //忽略服务器证书错误
+ CONFIG.IgnoreServerCertErrors = true;
+ CONFIG.bEnableIPv6 = false;
+ //CONFIG.bCaptureCONNECT = true;
+ //CONFIG.bUseEventLogForExceptions = false;
+ //CONFIG.bAutoProxyLogon = false;
+ //CONFIG.bMITM_HTTPS = false;
+ ////CONFIG.SetNoDecryptList("*");
+ }
+
+
+ private void FiddlerApplication_OnWebSocketMessage(object sender, WebSocketMessageEventArgs e)
+ {
+ var msg = e.oWSM;
+
+ FieldInfo field = msg.GetType().GetField("_wsOwner", BindingFlags.NonPublic | BindingFlags.Instance);
+ WebSocket obj = (WebSocket)field.GetValue(msg);
+ field = obj.GetType().GetField("oCP", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ var sessionField = obj.GetType().GetField("_mySession", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ ClientPipe ocp = (ClientPipe)field.GetValue(obj);
+ Session session = (Session)sessionField.GetValue(obj);
+
+ this.SendWebSocketData(new WsMessageEventArgs()
+ {
+ Payload = msg.PayloadData,
+ ProcessID = ocp.LocalProcessID,
+ ProcessName = ocp.LocalProcessName,
+ HostName = session.hostname,
+ });
+ }
+
+
+ public override void Start()
+ {
+ FiddlerApplication.Startup(Appsetting.Instanse.ProxyPort, FiddlerCoreStartupFlags.Default);
+ console.WriteLine("Fiddler代理已启动", ConsoleColor.Green);
+ }
+
+ public override void Dispose()
+ {
+ if (disposed) return;
+ FiddlerApplication.Shutdown();
+ CloseSystemProxy();
+ console.WriteLine("Fiddler代理已关闭");
+ disposed = true;
+ }
+ }
+}
diff --git a/BarrageGrab/Proxy/ISystemProxy.cs b/BarrageGrab/Proxy/ISystemProxy.cs
new file mode 100644
index 0000000..9cccac0
--- /dev/null
+++ b/BarrageGrab/Proxy/ISystemProxy.cs
@@ -0,0 +1,40 @@
+using System;
+using Fiddler;
+using System.Reflection;
+
+namespace BarrageGrab.Proxy
+{
+ internal interface ISystemProxy : IDisposable
+ {
+ event EventHandler OnWebSocketData;
+
+ ///
+ /// 开始监听
+ ///
+ void Start();
+ }
+
+ public class WsMessageEventArgs
+ {
+ ///
+ /// 消息体
+ ///
+ public byte[] Payload { get; set; }
+
+ ///
+ /// 进程ID
+ ///
+ public int ProcessID { get; set; }
+
+ ///
+ /// 进程名
+ ///
+ public string ProcessName { get; set; }
+
+ ///
+ /// 域名
+ ///
+ public string HostName { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/BarrageGrab/Proxy/SystemProxy.cs b/BarrageGrab/Proxy/SystemProxy.cs
new file mode 100644
index 0000000..8c847e5
--- /dev/null
+++ b/BarrageGrab/Proxy/SystemProxy.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Win32;
+using System.Diagnostics;
+
+namespace BarrageGrab.Proxy
+{
+ internal abstract class SystemProxy : ISystemProxy
+ {
+ //弹幕服务域名
+ protected string[] barrageWsHostNames = new string[]
+ {
+ "webcast3-ws-web-hl.douyin.com",
+ "webcast3-ws-web-lf.douyin.com",
+ "frontier-im.douyin.com"
+ };
+
+
+ //https://live.douyin.com/webcast/gift/list/
+
+ ///
+ /// 接收到websocket消息事件
+ ///
+ public event EventHandler OnWebSocketData;
+
+ ///
+ /// 代理端口
+ ///
+ public int ProxyPort { get => Appsetting.Instanse.ProxyPort; }
+
+ public abstract void Dispose();
+
+ public abstract void Start();
+
+ protected void SendWebSocketData(WsMessageEventArgs args)
+ {
+ OnWebSocketData?.Invoke(this, args);
+ }
+
+ protected string GetProcessName(int processID)
+ {
+ var process = Process.GetProcessById(processID);
+ if (process != null)
+ {
+ return process.ProcessName;
+ }
+ return $"<{processID}>";
+ }
+
+ // 生成自签名证书
+ protected X509Certificate2 EnsureCertificate(string subjectName)
+ {
+ // 添加证书到证书存储
+ var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
+ store.Open(OpenFlags.ReadWrite);
+ //判断证书是否已经存在
+ var certificates = store.Certificates.Find(X509FindType.FindBySubjectName, subjectName, false);
+ if (certificates.Count > 0)
+ {
+ return certificates[0];
+ }
+
+ // 创建证书请求
+ var request = new CertificateRequest($"CN={subjectName}", RSA.Create(2048), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
+
+ // 添加扩展属性
+ request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
+ request.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false));
+ request.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(request.PublicKey, false));
+
+ // 用自己的私钥签名并生成证书
+ var certificate = request.CreateSelfSigned(DateTimeOffset.Now.AddDays(-1), DateTimeOffset.Now.AddDays(365));
+ store.Add(certificate);
+ store.Close();
+
+ return certificate;
+ }
+
+ //注册系统代理
+ protected void RegisterSystemProxy()
+ {
+ RegistryKey registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
+ registry.SetValue("ProxyEnable", 1);
+ registry.SetValue("ProxyServer", $"http=localhost:{ProxyPort};https=localhost:{ProxyPort}");
+ }
+
+ ///
+ /// 关闭系统代理
+ ///
+ protected void CloseSystemProxy()
+ {
+ RegistryKey registry = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
+ registry.SetValue("ProxyEnable", 0);
+ registry.SetValue("ProxyServer", $"http=localhost:{ProxyPort};https=localhost:{ProxyPort}");
+ }
+ }
+}
diff --git a/BarrageGrab/Proxy/TitaniumProxy.cs b/BarrageGrab/Proxy/TitaniumProxy.cs
new file mode 100644
index 0000000..4b8938b
--- /dev/null
+++ b/BarrageGrab/Proxy/TitaniumProxy.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Security;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Win32;
+using Titanium.Web.Proxy;
+using Titanium.Web.Proxy.EventArguments;
+using Titanium.Web.Proxy.Http;
+using Titanium.Web.Proxy.Models;
+using Titanium.Web.Proxy.StreamExtended.Network;
+
+namespace BarrageGrab.Proxy
+{
+ internal class TitaniumProxy : SystemProxy
+ {
+ ProxyServer proxyServer = null;
+ ExplicitProxyEndPoint explicitEndPoint = null;
+
+ public TitaniumProxy()
+ {
+ //注册系统代理
+ //RegisterSystemProxy();
+ proxyServer = new ProxyServer();
+
+ //var cert = EnsureCertificate("localhost");
+
+ proxyServer.ReuseSocket = false;
+ proxyServer.EnableConnectionPool = true;
+ proxyServer.ForwardToUpstreamGateway = true;
+ proxyServer.CertificateManager.SaveFakeCertificates = true;
+
+ proxyServer.ServerCertificateValidationCallback += ProxyServer_ServerCertificateValidationCallback; ;
+ proxyServer.BeforeResponse += ProxyServer_BeforeResponse;
+
+ explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any,ProxyPort, true);
+ explicitEndPoint.BeforeTunnelConnectRequest += ExplicitEndPoint_BeforeTunnelConnectRequest;
+ proxyServer.AddEndPoint(explicitEndPoint);
+ }
+
+
+ private Task ProxyServer_ServerCertificateValidationCallback(object sender, CertificateValidationEventArgs e)
+ {
+ // set IsValid to true/false based on Certificate Errors
+ if (e.SslPolicyErrors == SslPolicyErrors.None)
+ {
+ e.IsValid = true;
+ }
+
+ return Task.CompletedTask;
+ }
+
+
+ private async Task ProxyServer_BeforeResponse(object sender, SessionEventArgs e)
+ {
+ string hostname = e.HttpClient.Request.RequestUri.Host;
+ if (!barrageWsHostNames.Contains(hostname)) return;
+
+ if (e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Websocket)
+ {
+ e.DataReceived += WebSocket_DataReceived;
+ }
+ }
+
+ //List hostlist = new List();
+
+ private async Task ExplicitEndPoint_BeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
+ {
+ string hostname = e.HttpClient.Request.RequestUri.Host;
+ if (!barrageWsHostNames.Contains(hostname))
+ {
+ e.DecryptSsl = false;
+ }
+ }
+
+ private async void WebSocket_DataReceived(object sender, DataEventArgs e)
+ {
+ var args = (SessionEventArgs)sender;
+
+ string hostname = args.HttpClient.Request.RequestUri.Host;
+
+ var processid = args.HttpClient.ProcessId.Value;
+
+ var frames = args.WebSocketDecoderReceive.Decode(e.Buffer, e.Offset, e.Count).ToList();
+ //Console.WriteLine(frames.Count);
+
+ foreach (var frame in frames)
+ {
+ //Console.WriteLine(frame.GetText());
+ base.SendWebSocketData(new WsMessageEventArgs()
+ {
+ ProcessID = processid,
+ HostName = hostname,
+ Payload = frame.Data.ToArray(),
+ ProcessName = base.GetProcessName(processid)
+ });
+ }
+ //Console.WriteLine("获取到弹幕信息:" + hostname);
+
+
+ }
+
+ ///
+ /// 释放资源,关闭系统代理
+ ///
+ override public void Dispose()
+ {
+ proxyServer.Stop();
+ proxyServer.Dispose();
+ CloseSystemProxy();
+ }
+
+ ///
+ /// 启动监听
+ ///
+ override public void Start()
+ {
+ proxyServer.Start();
+ proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
+ proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
+ }
+ }
+}
diff --git a/BarrageGrab/WssBarrageGrab.cs b/BarrageGrab/WssBarrageGrab.cs
index 8d2a961..33287ea 100644
--- a/BarrageGrab/WssBarrageGrab.cs
+++ b/BarrageGrab/WssBarrageGrab.cs
@@ -8,6 +8,7 @@ using System.Threading.Tasks;
using BarrageGrab.ProtoEntity;
using ProtoBuf;
using ColorConsole;
+using BarrageGrab.Proxy;
namespace BarrageGrab
{
@@ -16,7 +17,8 @@ namespace BarrageGrab
///
public class WssBarrageGrab : IDisposable
{
- FiddlerProxy proxy = new FiddlerProxy();
+ //ISystemProxy proxy = new FiddlerProxy();
+ ISystemProxy proxy = new TitaniumProxy();
Appsetting appsetting = Appsetting.Get();
ConsoleWriter console = new ConsoleWriter();
@@ -94,13 +96,14 @@ namespace BarrageGrab
return outBuffer.ToArray();
}
- private void Proxy_OnWebSocketData(object sender, FiddlerProxy.WsMessageEventArgs e)
+ private void Proxy_OnWebSocketData(object sender, WsMessageEventArgs e)
{
if (!appsetting.FilterProcess.Contains(e.ProcessName)) return;
- var buff = e.Message.PayloadData;
+ var buff = e.Payload;
if (buff.Length == 0) return;
if (buff[0] != 0x08) return;
+
try
{
var enty = Serializer.Deserialize(new ReadOnlyMemory(buff));
@@ -109,6 +112,7 @@ namespace BarrageGrab
//检测包格式
if (!enty.Headers.Any(a => a.Key == "compress_type" && a.Value == "gzip")) return;
+
//解压gzip
var odata = enty.Payload;
var decomp = Decompress(odata);
diff --git a/BarrageGrab/WssBarrageService.cs b/BarrageGrab/WssBarrageService.cs
index 5fa5724..e46a2ec 100644
--- a/BarrageGrab/WssBarrageService.cs
+++ b/BarrageGrab/WssBarrageService.cs
@@ -23,7 +23,7 @@ namespace BarrageGrab
ConsoleWriter console = new ConsoleWriter();
WssBarrageGrab grab = new WssBarrageGrab();
Appsetting Appsetting = Appsetting.Get();
-
+
public WssBarrageService()
{
var socket = new WebSocketServer($"ws://127.0.0.1:{Appsetting.WsProt}");
@@ -96,7 +96,7 @@ namespace BarrageGrab
{
RoomId = e.Common.roomId,
Content = e.Common.Describe,
- GiamondCount = e.Gift.diamondCount,
+ DiamondCount = e.Gift.diamondCount,
GiftCount = e.repeatCount,
GiftId = e.giftId,
GiftName = e.Gift.Name,
diff --git a/BarrageGrab/WssBarrageService.csproj b/BarrageGrab/WssBarrageService.csproj
index 2e0ec19..32b5ed1 100644
--- a/BarrageGrab/WssBarrageService.csproj
+++ b/BarrageGrab/WssBarrageService.csproj
@@ -50,18 +50,24 @@
..\packages\FiddlerCore.4.6.2.0\lib\net40\BCMakeCert.dll
+
+ ..\packages\Portable.BouncyCastle.1.8.8\lib\net40\BouncyCastle.Crypto.dll
+
+
+ ..\packages\BrotliSharpLib.0.3.3\lib\net451\BrotliSharpLib.dll
+
..\packages\FiddlerCore.4.6.2.0\lib\net40\CertMaker.dll
..\packages\ColorConsole.1.0.1\lib\net40\ColorConsole.dll
-
- ..\packages\FiddlerCore.4.6.2.0\lib\net40\FiddlerCore4.dll
-
..\packages\Fleck.1.2.0\lib\net45\Fleck.dll
+
+ ..\packages\Microsoft.Win32.Registry.5.0.0\lib\net461\Microsoft.Win32.Registry.dll
+
..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll
@@ -90,19 +96,33 @@
..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
+
+ ..\packages\System.Security.AccessControl.5.0.0\lib\net461\System.Security.AccessControl.dll
+
+
+ ..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll
+
+
+ ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
+
+
+ ..\packages\Titanium.Web.Proxy.3.2.0\lib\net461\Titanium.Web.Proxy.dll
+
+
+
+
-
diff --git a/BarrageGrab/packages.config b/BarrageGrab/packages.config
index 4665f8b..24a24dc 100644
--- a/BarrageGrab/packages.config
+++ b/BarrageGrab/packages.config
@@ -1,9 +1,12 @@
+
+
+
@@ -11,4 +14,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/BarrageService.sln b/BarrageService.sln
index c4ba32d..e55db5d 100644
--- a/BarrageService.sln
+++ b/BarrageService.sln
@@ -5,16 +5,32 @@ VisualStudioVersion = 17.2.32408.312
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WssBarrageService", "BarrageGrab\WssBarrageService.csproj", "{A07BB1DA-D5C2-4EEA-9F3F-E42AADB9C1D6}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FiddlerCore4", "FiddlerCore4\FiddlerCore4.csproj", "{6E137484-17DC-4AB2-A1BB-2E6E050A9F54}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A07BB1DA-D5C2-4EEA-9F3F-E42AADB9C1D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A07BB1DA-D5C2-4EEA-9F3F-E42AADB9C1D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A07BB1DA-D5C2-4EEA-9F3F-E42AADB9C1D6}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A07BB1DA-D5C2-4EEA-9F3F-E42AADB9C1D6}.Debug|x86.Build.0 = Debug|Any CPU
{A07BB1DA-D5C2-4EEA-9F3F-E42AADB9C1D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A07BB1DA-D5C2-4EEA-9F3F-E42AADB9C1D6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A07BB1DA-D5C2-4EEA-9F3F-E42AADB9C1D6}.Release|x86.ActiveCfg = Release|Any CPU
+ {A07BB1DA-D5C2-4EEA-9F3F-E42AADB9C1D6}.Release|x86.Build.0 = Release|Any CPU
+ {6E137484-17DC-4AB2-A1BB-2E6E050A9F54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6E137484-17DC-4AB2-A1BB-2E6E050A9F54}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6E137484-17DC-4AB2-A1BB-2E6E050A9F54}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6E137484-17DC-4AB2-A1BB-2E6E050A9F54}.Debug|x86.Build.0 = Debug|Any CPU
+ {6E137484-17DC-4AB2-A1BB-2E6E050A9F54}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6E137484-17DC-4AB2-A1BB-2E6E050A9F54}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6E137484-17DC-4AB2-A1BB-2E6E050A9F54}.Release|x86.ActiveCfg = Release|Any CPU
+ {6E137484-17DC-4AB2-A1BB-2E6E050A9F54}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE