亲友传真---海外信息直接看 https://qycz.org
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace Torhelper
{
internal class Program
{
private static Dictionary<int, string> _processMap = new Dictionary<int, string>();
private static List<string> torrclist = new List<string>();
private static List<string> polipoconfiglist = new List<string>();
private static List<string> awaitingDeletion = new List<string>();
private static string iniconfigpath,
proxyswitchpath,
proxyswitchproxylistpath;
private static string Torexepath, Torbridgedbpath, lyrebirdpath, webtunnelclientpath,
Polipoexepath;
private const int MF_BYCOMMAND = 0x00000000;
private const int SC_CLOSE = 0xF060;
private const int MF_GRAYED = 0x00000001;
private static int deletetorcache = 0;
[DllImport("user32.dll")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
private static extern int EnableMenuItem(IntPtr hMenu, int uIDEnableItem, int uEnable);
[DllImport("kernel32.dll")]
private static extern IntPtr GetConsoleWindow();
// 禁用 Ctrl+C 的 Win32 API
[DllImport("kernel32.dll")]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlHandler handler, bool add);
// 定义控制台事件处理委托
private delegate bool ConsoleCtrlHandler(CtrlType ctrlType);
private enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6,
}
private static string proxytype = "https",
proxyaddress = "127.0.0.1:8580";
private static int torcount = 5,
starttorport = 9050,
startpolipoport = 8118;
private static readonly string[] torrcpublic =
{
"SocksListenAddress 127.0.0.1",
//"ExcludeNodes {cn},{hk},{sg},{pk},{th},{mo}",
"ExcludeNodes {cn}",
"ReachableDirAddresses *:80",
"ReachableDirAddresses *:443",
"ReachableORAddresses *:443",
"ReachableORAddresses *:80",
"ReachableORAddresses *:22",
"ReachableORAddresses *:8443",
"ReachableORAddresses *:3389",
"ReachableORAddresses *:1080",
"ReachableORAddresses *:445",
"ReachableORAddresses *:3128",
"ReachableORAddresses *:8080"
};
private static readonly string[] polipoconfigpublic =
{
"proxyAddress = \"127.0.0.1\"",
"allowedClients = 127.0.0.1",
"allowedPorts = 1-65535",
"proxyName = \"localhost\"",
"cacheIsShared = false",
"socksProxyType = socks5",
"chunkHighMark = 33554432",
"diskCacheRoot = \"\"",
"localDocumentRoot = \"\"",
"disableLocalInterface = true",
"disableConfiguration = true",
"dnsUseGethostbyname = yes",
"disableVia = true",
"censoredHeaders = from,accept-language,x-pad,link",
"censorReferer = maybe",
"maxConnectionAge = 5m",
"maxConnectionRequests = 120",
"serverMaxSlots = 8",
"serverSlots = 2",
"tunnelAllowedPorts = 1-65535",
};
private static void Main()
{
IntPtr handle = GetConsoleWindow();
if (handle != IntPtr.Zero)
{
IntPtr sysMenu = GetSystemMenu(handle, false);
EnableMenuItem(sysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
}
RegistryKey tweakMarketingKey = Registry.CurrentUser.CreateSubKey(
@"Software\Tweak Marketing"
);
RegistryKey proxySwitchKey = tweakMarketingKey.CreateSubKey("Proxy Switch");
RegistryKey registrationKey = proxySwitchKey.CreateSubKey("Registration");
proxySwitchKey.SetValue("NumProxyErrors", 0001869f, RegistryValueKind.DWord);
/*
proxySwitchKey.SetValue("FileHash", "201622", RegistryValueKind.String);
proxySwitchKey.SetValue("ListenPort", 0x00000c38, RegistryValueKind.DWord);
proxySwitchKey.SetValue("Timeout", 0x00000002, RegistryValueKind.DWord);
proxySwitchKey.SetValue("NumProxyErrors", 0x0000000a, RegistryValueKind.DWord);
proxySwitchKey.SetValue("SavingPeriod", 0x00000003, RegistryValueKind.DWord);
proxySwitchKey.SetValue("SocketBufSize", 0x00000002, RegistryValueKind.DWord);
proxySwitchKey.SetValue("Switch", 0x00000000, RegistryValueKind.DWord);
proxySwitchKey.SetValue("SwitchConnectionsValue", 0x00000005, RegistryValueKind.DWord);
proxySwitchKey.SetValue("SwitchEverySecondsValue", 0x0000001e, RegistryValueKind.DWord);
proxySwitchKey.SetValue("SwitchSecondsValue", 0x0000001e, RegistryValueKind.DWord);
proxySwitchKey.SetValue("SwitchKBytesValue", 0x00000064, RegistryValueKind.DWord);
proxySwitchKey.SetValue("BindRadio", 0x00000001, RegistryValueKind.DWord);
proxySwitchKey.SetValue("BindInterface0", "127.0.0.1", RegistryValueKind.String);
proxySwitchKey.SetValue("BindInterface1", "192.168.1.49", RegistryValueKind.String);
proxySwitchKey.SetValue("IpMask0", "y127.0.0.1", RegistryValueKind.String);
proxySwitchKey.SetValue("IpMask1", "y10.*.*.*", RegistryValueKind.String);
proxySwitchKey.SetValue("IpMask2", "y172.16.0.0/12", RegistryValueKind.String);
proxySwitchKey.SetValue("IpMask3", "y192.168.*.*", RegistryValueKind.String);
proxySwitchKey.SetValue("FileOpenReplace", 0x00000000, RegistryValueKind.DWord);
proxySwitchKey.SetValue("FileOpenNoDups", 0x00000000, RegistryValueKind.DWord);
registrationKey.SetValue("Code", "KPS-82WLP-GKTF7MZ3CX", RegistryValueKind.String);
// 关闭键
registrationKey.Close();
proxySwitchKey.Close();
tweakMarketingKey.Close();
*/
//注册 proxy switch
string registryPath = @"Software\Tweak Marketing\Proxy Switch\Registration";
string keyName = "Code";
string keyValue = "KPS-82WLP-GKTF7MZ3CX";
try
{
RegistryKey registryKey = Registry.CurrentUser.CreateSubKey(registryPath);
registryKey.SetValue(keyName, keyValue);
registryKey.Close();
}
catch (Exception ex)
{
Console.WriteLine("注册ProxySwitch时出错: " + ex.Message);
}
string currentDirectory = Directory.GetCurrentDirectory();
// Data 目录用于存储tor 和 polipo的配置和Tor数据目录
string dataDirectory = Path.Combine(currentDirectory, "Data");
string chromecacheDirectory = Path.Combine(currentDirectory, "Cache");
if (!Directory.Exists(chromecacheDirectory))
{
Directory.CreateDirectory(chromecacheDirectory);
}
string chromebindir = Path.Combine(currentDirectory, "App", "chrome-win");
string chromebinpath = Path.Combine(
currentDirectory,
"App",
"chrome-win",
"chrome.exe"
);
if (!Directory.Exists(dataDirectory))
{
Directory.CreateDirectory(dataDirectory);
}
Torexepath = Path.Combine(currentDirectory, "App", "tor.exe");
lyrebirdpath= Path.Combine(currentDirectory, "App", "Pluggable_Transports", "lyrebird.exe");
webtunnelclientpath = Path.Combine(currentDirectory, "App", "Pluggable_Transports", "webtunnel-client.exe");
Torbridgedbpath = Path.Combine(currentDirectory, "App", "bridges.txt");
Polipoexepath = Path.Combine(currentDirectory, "App", "polipo.exe");
string geiopath = Path.Combine(currentDirectory, "App", "geoip.txt");
string geio6path = Path.Combine(currentDirectory, "App", "geoip6.txt");
iniconfigpath = Path.Combine(currentDirectory, "config.ini");
proxyswitchpath = Path.Combine(
currentDirectory,
"App",
"Proxy Switch",
"ProxySwitch.exe"
);
proxyswitchproxylistpath = Path.Combine(
currentDirectory,
"App",
"Proxy Switch",
"Proxies.psl"
);
//读取用户配置
IniFiles myconf = new IniFiles(iniconfigpath);
if (!File.Exists(iniconfigpath))
{
myconf.IniWriteValue("config", "proxytype", proxytype);
myconf.IniWriteValue("config", "proxyaddress", proxyaddress);
myconf.IniWriteValue("config", "torcount", torcount.ToString());
myconf.IniWriteValue("config", "starttorport", starttorport.ToString());
myconf.IniWriteValue("config", "startpolipoport", startpolipoport.ToString());
myconf.IniWriteValue("config", "deletetorcache", deletetorcache.ToString());
}
else
{
proxytype = myconf.IniReadValue("config", "proxytype");
proxyaddress = myconf.IniReadValue("config", "proxyaddress");
torcount = Convert.ToInt32(myconf.IniReadValue("config", "torcount"));
starttorport = Convert.ToInt32(myconf.IniReadValue("config", "starttorport"));
startpolipoport = Convert.ToInt32(myconf.IniReadValue("config", "startpolipoport"));
deletetorcache = Convert.ToInt32(myconf.IniReadValue("config", "deletetorcache"));
}
//检测配置文件中所有要使用到的端口是否被其它进程占用 如果是则要先结束占用端口的进程 0329 应该放到读取ini代码之后
List<int> ourportlist = new List<int>();
for (int index = 0; index < torcount; index++)
{
ourportlist.Add(starttorport + index);
ourportlist.Add(startpolipoport + index);
}
ourportlist.Add(3128);
foreach (int port in ourportlist)
{
if (IsPortInUse(port))
{
int pid = GetProcessIdUsingPort(port);
if (pid != -1)
{
Console.WriteLine($"检测到占用设置端口的进程ID: {pid} 准备强行结束对应进程释放");
KillProcessById(pid);
}
else
{
//Console.WriteLine($"Torhelper中配置的端口{port}没有被占用");
}
}
}
//写入 Proxies.psl
if (File.Exists(proxyswitchproxylistpath))
{
File.Delete(proxyswitchproxylistpath);
}
string[] switchlist = new string[torcount];
for (int i = startpolipoport; i < startpolipoport + torcount; i++)
{
string temp = "127.0.0.1:" + i.ToString() + ";0;0;1";
switchlist[i - startpolipoport] = temp;
}
using (StreamWriter writer = new StreamWriter(proxyswitchproxylistpath, true)) // true 表示追加写入
{
foreach (string line in switchlist)
{
writer.WriteLine(line);
}
}
// 自动写 tor 和 polipo 配置文件模块
for (int i = 0; i < torcount; i++)
{
var tordata = Path.Combine(dataDirectory, "Tor_" + i.ToString().PadLeft(2, '0'));
var polipodata = Path.Combine(
dataDirectory,
"Polipo_" + i.ToString().PadLeft(2, '0')
);
awaitingDeletion.Add(tordata);
awaitingDeletion.Add(polipodata);
if (!Directory.Exists(tordata))
{
Directory.CreateDirectory(tordata);
}
if (!Directory.Exists(polipodata))
{
Directory.CreateDirectory(polipodata);
}
var torrcpath = Path.Combine(tordata, "torrc.txt");
var polipopath = Path.Combine(polipodata, "polipo.conf");
torrclist.Add(torrcpath);
polipoconfiglist.Add(polipopath);
List<string> torrctemp = torrcpublic.ToList();
torrctemp.Add("DataDirectory " + tordata);
torrctemp.Add("SocksPort " + (i + starttorport).ToString());
torrctemp.Add("GeoIPFile " + geiopath);
torrctemp.Add("GeoIPv6File " + geio6path);
if (File.Exists(Torbridgedbpath))
{
torrctemp.Add("UseBridges 1");
string[] bridgetemp = GetRandomLines(Torbridgedbpath, 12);//从App下bridges.txt 随机抽取10行网桥
foreach (string bridge in bridgetemp)
{
torrctemp.Add("Bridge " + bridge);
}
torrctemp.Add("ClientTransportPlugin obfs4 exec "+lyrebirdpath);
torrctemp.Add("ClientTransportPlugin webtunnel exec " + webtunnelclientpath);
}
else//如果不存在 bridge.txt 则根据ini的用户设定配置前置代理
{
if (proxytype == "socks")
{
torrctemp.Add("Socks5Proxy " + proxyaddress);
}
else if (proxytype == "https")
{
torrctemp.Add("HttpProxy " + proxyaddress);
torrctemp.Add("HttpsProxy " + proxyaddress);
}
}
using (StreamWriter writer = new StreamWriter(torrcpath, true))
{
foreach (string line in torrctemp)
{
writer.WriteLine(line);
}
}
StartTor(Torexepath, torrcpath);
List<string> polipocfgtemp = polipoconfigpublic.ToList();
polipocfgtemp.Add("proxyPort = " + (i + startpolipoport));
polipocfgtemp.Add("socksParentProxy = 127.0.0.1:" + (i + starttorport));
using (StreamWriter writer = new StreamWriter(polipopath, true))
{
foreach (string line in polipocfgtemp)
{
writer.WriteLine(line);
}
}
StartPolipo(Polipoexepath, polipopath);
}
//启动 proxy switch
if (File.Exists(proxyswitchpath))
{
try
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = proxyswitchpath,
WorkingDirectory = currentDirectory,
UseShellExecute = true,
CreateNoWindow = false,
};
Process process = Process.Start(startInfo);
_processMap.Add(process.Id, proxyswitchpath);
Console.WriteLine(
"ProxySwitch 代理调度机制已成功启动 请将浏览器和下载工具代理设置为 127.0.0.1:3128 使用"
);
}
catch (Exception ex)
{
Console.WriteLine("启动 proxyProxySwitchswitch 时出错: " + ex.Message);
}
}
else
{
Console.WriteLine("ProxySwitch.exe 不存在");
}
if (File.Exists(chromebinpath))
{
try
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = chromebinpath,
WorkingDirectory = chromebindir,
UseShellExecute = true,
CreateNoWindow = false,
Arguments =
$"--user-data-dir=\"{chromecacheDirectory}\" --no-default-browser-check --disable-logging --disable-breakpad --proxy-server=127.0.0.1:3128 --disk-cache-size=1 --disable-client-side-phishing-detection --disable-component-extensions-with-background-pages --disable-default-apps --disable-features=InterestFeedContentSuggestions --disable-features=Translate --no-first-run --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-ipc-flooding-protection --disable-renderer-backgrounding --use-fake-device-for-media-stream --disable-external-intent-requests", //故意把disk-cache-size设置为1强制chrome缓存走内存 提升速度
WindowStyle = ProcessWindowStyle.Maximized,
};
using (var process = new Process { StartInfo = startInfo })
{
process.Start();
_processMap.Add(process.Id, proxyswitchpath);
Console.WriteLine("Chrome 浏览器已启动 可以安全畅游");
}
}
catch (Exception ex)
{
Console.WriteLine("启动 Chrome 时出错: " + ex.Message);
}
}
else
{
Console.WriteLine("Chrome.exe 不存在");
}
SetConsoleCtrlHandler(ConsoleCtrlHandler2, true);
Console.WriteLine("输入 'exit' 退出程序...");
while (true)
{
string input = Console.ReadLine();
if (input != null && input.ToLower() == "exit")
{
break;
}
else
{
Console.WriteLine("无效输入,请输入 'exit' 退出程序。");
}
}
Cleanup();
}
private static string[] GetRandomLines(string filePath, int numberOfLines)//20250328
{
string[] allLines = File.ReadAllLines(filePath);
int availableLines = Math.Min(allLines.Length, numberOfLines);
Random rnd = new Random();
HashSet<int> selectedIndices = new HashSet<int>();
while (selectedIndices.Count < availableLines)
{
int randomIndex = rnd.Next(0, allLines.Length);
selectedIndices.Add(randomIndex);
}
string[] randomLines = new string[availableLines];
int i = 0;
foreach (int index in selectedIndices)
{
randomLines[i++] = allLines[index];
}
return randomLines;
}
private static void StartTor(string torpath, string configPath)
{
try
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = torpath,
Arguments = string.Format("-f \"{0}\"", configPath),
UseShellExecute = false,
CreateNoWindow = true,
},
};
if (process.Start())
{
_processMap.Add(process.Id, configPath);
Console.WriteLine("Tor 已启动进程 {0} : {1}", process.Id, configPath);
}
}
catch (Exception ex)
{
Console.WriteLine("Tor 启动失败: {0}", ex.Message);
}
}
private static void StartPolipo(string Polipopath, string configPath)
{
try
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = Polipopath,
Arguments = string.Format("-c \"{0}\"", configPath),
UseShellExecute = false,
CreateNoWindow = true,
},
};
if (process.Start())
{
_processMap.Add(process.Id, configPath);
Console.WriteLine("Polipo 已启动进程 {0} : {1}", process.Id, configPath);
}
}
catch (Exception ex)
{
Console.WriteLine("Polipo 启动失败: {0}", ex.Message);
}
}
private static bool ConsoleCtrlHandler2(CtrlType ctrlType)
{
if (
ctrlType == CtrlType.CTRL_CLOSE_EVENT
|| ctrlType == CtrlType.CTRL_C_EVENT
|| ctrlType == CtrlType.CTRL_SHUTDOWN_EVENT
|| ctrlType == CtrlType.CTRL_BREAK_EVENT
|| ctrlType == CtrlType.CTRL_LOGOFF_EVENT
)
{
Console.WriteLine("检测到软件被强行关闭或者退出 开始启动清理机制");
Cleanup();
}
return false;
}
private static bool IsPortInUse(int port)
{
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnInfoArray =
ipGlobalProperties.GetActiveTcpConnections();
return tcpConnInfoArray.Any(conn => conn.LocalEndPoint.Port == port);
}
private static int GetProcessIdUsingPort(int port)
{
var query = $"SELECT * FROM Win32_TCPIPPrinterPort WHERE PortNumber = {port}";
using (var searcher = new ManagementObjectSearcher(query))
{
foreach (ManagementObject obj in searcher.Get())
{
var pid = Convert.ToInt32(obj["ProcessID"]);
return pid;
}
}
return -1;
}
private static void KillProcessById(int pid)
{
try
{
Process process = Process.GetProcessById(pid);
Console.WriteLine(
$"正在结束占用端口的进程: {process.ProcessName} (PID: {pid}) "
+ process.MainModule.ModuleName
);
process.Kill();
process.WaitForExit();
Console.WriteLine("进程已结束。");
}
catch (ArgumentException ex)
{
Console.WriteLine($"无法找到进程ID为 {pid} 的进程: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"结束进程时出错: {ex.Message}");
}
}
private static void Cleanup()
{
foreach (var pid in new List<int>(_processMap.Keys))
{
try
{
using (var process = Process.GetProcessById(pid))
{
if (
IsTargetProcess(process, _processMap[pid])
|| process.MainModule.ModuleName.Contains("ProxySwitch.exe")
) //|| process.MainModule.ModuleName.Contains("chrome")
{
KillProcessTree(pid);
Console.WriteLine("已终止进程 {0}", pid);
}
}
}
catch (ArgumentException)
{ /* 进程已退出 */
}
catch (Exception ex)
{
Console.WriteLine("终止失败: {0}", ex.Message);
}
}
foreach (var file in torrclist)
{
if (File.Exists(file))
{
File.Delete(file);
}
}
foreach (var file in polipoconfiglist)
{
if (File.Exists(file))
{
File.Delete(file);
}
}
if (deletetorcache == 1)
{
foreach (string dir in awaitingDeletion)
{
if (Directory.Exists(dir))
{
Directory.Delete(dir, true);
}
}
}
}
private static bool IsTargetProcess(Process process, string expectedConfig)
{
try
{
var cmdLine = GetCommandLineWmi(process.Id);
return cmdLine.Contains(string.Format("-c \"{0}\"", expectedConfig))
|| cmdLine.Contains(string.Format("-f \"{0}\"", expectedConfig));
}
catch
{
return false;
}
}
private static string GetCommandLineWmi(int processId)
{
using (
var searcher = new ManagementObjectSearcher(
string.Format(
"SELECT CommandLine FROM Win32_Process WHERE ProcessId = {0}",
processId
)
)
)
{
foreach (ManagementObject mo in searcher.Get())
{
if (mo["CommandLine"] != null) // 手动检查是否为 null
{
return mo["CommandLine"].ToString();
}
return ""; // 如果为 null,返回空字符串
}
}
return "";
}
private static void KillProcessTree(int pid)
{
try
{
var searcher = new ManagementObjectSearcher(
string.Format(
"SELECT ProcessId FROM Win32_Process WHERE ParentProcessId={0}",
pid
)
);
foreach (ManagementObject mo in searcher.Get())
{
int childPid = Convert.ToInt32(mo["ProcessId"]);
KillProcessTree(childPid);
}
using (var process = Process.GetProcessById(pid))
{
if (!process.HasExited)
{
process.Kill();
process.WaitForExit(5000);
}
}
}
catch
{ /* 忽略所有异常 */
}
}
}
}
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
public class IniFiles
{
public string inipath;
[DllImport("Kernel32.dll")]
private static extern int GetPrivateProfileString(string strAppName, string strKeyName, string strDefault, StringBuilder sbReturnString, int nSize, string strFileName);
[DllImport("Kernel32.dll")]
private extern static int GetPrivateProfileStringA(string strAppName, string strKeyName, string sDefault, byte[] buffer, int nSize, string strFileName);
[DllImport("Kernel32.dll")]
private static extern int GetPrivateProfileInt(string strAppName, string strKeyName, int nDefault, string strFileName);
[DllImport("Kernel32.dll")]
private extern static int GetPrivateProfileSectionNamesA(byte[] buffer, int iLen, string fileName);
[DllImport("Kernel32.dll")]
private static extern int GetPrivateProfileSection(string lpAppName, byte[] lpReturnedString, int nSize, string lpFileName);
[DllImport("Kernel32.dll")]
public static extern long WritePrivateProfileString(string strAppName, string strKeyName, string strKeyValue, string strFileName);
[DllImport("Kernel32.dll")]
public static extern long WritePrivateProfileSection(string strAppName, string strkeyandvalue, string strFileName);
public IniFiles(string INIPath)
{
inipath = INIPath;
}
public IniFiles() { }
public void IniWriteValue(string Section, string Key, string Value)
{
WritePrivateProfileString(Section, Key, Value, this.inipath);
}
public string IniReadValue(string Section, string Key)
{
StringBuilder temp = new StringBuilder(500);
int i = GetPrivateProfileString(Section, Key, "", temp, 500, this.inipath);
return temp.ToString();
}
public bool ExistINIFile()
{
return File.Exists(inipath);
}
public ArrayList ReadSections()
{
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int rel = GetPrivateProfileSectionNamesA(buffer, buffer.Length, this.inipath);
if (rel > buffer.Length)
{
bufferSize = rel;
buffer = new byte[bufferSize];
rel = GetPrivateProfileSectionNamesA(buffer, buffer.Length, this.inipath);
}
int iCnt, iPos;
ArrayList arrayList = new ArrayList();
string tmp;
if (rel > 0)
{
iCnt = 0;
iPos = 0;
for (iCnt = 0; iCnt < rel; iCnt++)
{
if (buffer[iCnt] == 0x00)
{
tmp = Encoding.ASCII.GetString(buffer, iPos, iCnt - iPos).Trim();
iPos = iCnt + 1;
if (tmp != "")
arrayList.Add(tmp);
}
}
}
return arrayList;
}
}
在 0.038 秒内创建了带有 13 查询的页面。