Hide your real IP in every Windows app at once — free tool routes browsers, messengers, and games through Tor
Route any Windows app through Tor — system-wide or app-by-app, one click.
Scans the Tor Browser SOCKS5 port automatically. No config files. No manual setup.
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
🔍 How it works
Install Tor Browser normally. Run this tool. It handles the rest:
1 — Port scan
Finds Tor Browser’s active SOCKS5 port by scanning the process PID. If that fails, brute-forces ports 9000–9500 with an actual SOCKS5 handshake (\x05\x01\x00) to verify — not just a TCP ping.
2 — System-wide mode
Writes socks5=127.0.0.1:PORT directly into the Windows Registry (HKCU\...\Internet Settings), then calls InternetSetOptionW to refresh WinInet instantly — no restart required. One click to enable, one click to revert.
3 — Per-app mode (Ctrl+click or Shift+click to select multiple)
- Chrome / Brave / Chromium → relaunches with
--proxy-server=socks5://127.0.0.1:PORTand openscheck.torproject.orgto confirm - Firefox → creates an isolated temp profile with
-no-remote, routes via env proxy vars - Everything else (Telegram, Discord, etc.) → use system-wide mode, then open the app
Known limit: Chrome/Telegram per-app routing can fail on some setups — enable system-wide mode before launching those if that happens. Will be fixed in a future update. Exit country switching is also coming.
→ For Telegram, Discord, games: these apps bypass WinInet entirely. The packet-level fix is Netch — it routes by PID using WinDivert at the kernel packet layer, no system-wide proxy needed.
Warning: Don’t enable system-wide mode on a machine with sensitive data — some apps bypass SOCKS or leak DNS. Use it on a clean/throwaway session.
💻 The code
import sys
import os
import subprocess
import socket
import threading
import time
import re
import psutil
import winreg
import ctypes
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QFont
class TorPortScanner:
def __init__(self):
self.found_ports = []
self.active_port = None
def find_tor_process_ports(self):
ports = []
try:
tor_pids = []
for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
try:
name = proc.info['name'].lower() if proc.info['name'] else ''
cmdline = ' '.join(proc.info['cmdline'] or []).lower()
if ('tor' in name or 'firefox' in name) and ('tor' in cmdline or 'browser' in cmdline or 'firefox' in name.lower()):
tor_pids.append(proc.info['pid'])
print(f"[DEBUG] Found Tor process: PID={proc.info['pid']}, name={name}")
except:
continue
if not tor_pids:
for proc in psutil.process_iter(['pid', 'name']):
try:
tor_pids.append(proc.info['pid'])
except:
continue
for pid in tor_pids:
if sys.platform == "win32":
cmd = f"netstat -ano | findstr {pid}"
try:
output = subprocess.check_output(cmd, shell=True, text=True)
for line in output.splitlines():
if "LISTENING" in line or "LISTEN" in line:
match = re.search(r":(\d{4,5})", line)
if match:
port = int(match.group(1))
if 9000 <= port <= 9500:
ports.append(port)
print(f"[DEBUG] Found port {port} via PID {pid}")
except:
pass
except Exception as e:
print(f"[DEBUG] Process search error: {e}")
return list(set(ports))
def brute_force_scan(self):
found = []
print("[DEBUG] Starting brute force scan...")
for port in range(9000, 9501):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(0.1)
result = sock.connect_ex(('127.0.0.1', port))
if result == 0:
try:
sock.send(b'\x05\x01\x00')
data = sock.recv(2)
if data and data[0] == 0x05:
found.append(port)
print(f"[DEBUG] Found SOCKS5 port: {port}")
except:
pass
sock.close()
except:
continue
return found
def test_socks_proxy(self, port, timeout=3):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
result = sock.connect_ex(('127.0.0.1', port))
if result == 0:
sock.send(b'\x05\x01\x00')
data = sock.recv(2)
sock.close()
if data and data[0] == 0x05:
return True
sock.close()
except Exception as e:
print(f"[DEBUG] Error checking port {port}: {e}")
return False
def full_scan(self, progress_callback=None):
self.found_ports = []
if progress_callback:
progress_callback("Searching for Tor process...")
ports_from_process = self.find_tor_process_ports()
if ports_from_process:
self.found_ports.extend(ports_from_process)
if progress_callback:
progress_callback(f"Found via process: {ports_from_process}")
if not self.found_ports:
if progress_callback:
progress_callback("Extended port scanning (9000-9500)...")
ports_from_bruteforce = self.brute_force_scan()
if ports_from_bruteforce:
self.found_ports.extend(ports_from_bruteforce)
if progress_callback:
progress_callback(f"Found via brute force: {ports_from_bruteforce}")
self.found_ports = list(set(self.found_ports))
valid_ports = []
if self.found_ports:
if progress_callback:
progress_callback(f"Checking {len(self.found_ports)} ports for SOCKS5...")
for i, p in enumerate(self.found_ports):
if progress_callback:
progress_callback(f"Checking port {p} ({i+1}/{len(self.found_ports)})...")
if self.test_socks_proxy(p):
valid_ports.append(p)
if progress_callback:
progress_callback(f"Port {p} ✓ WORKING (SOCKS5)")
else:
if progress_callback:
progress_callback(f"Port {p} ✗ Not responding to SOCKS5")
self.found_ports = valid_ports
return self.found_ports
class TorStarter(QThread):
log_signal = pyqtSignal(str)
finished_signal = pyqtSignal(bool)
def __init__(self, scanner=None):
super().__init__()
self.scanner = scanner
def run(self):
paths = []
if sys.platform == "win32":
user = os.getlogin()
paths = [
r"C:\Program Files\Tor Browser\Browser\firefox.exe",
rf"C:\Users\{user}\Desktop\Tor Browser\Browser\firefox.exe",
rf"C:\Users\{user}\Downloads\Tor Browser\Browser\firefox.exe"
]
elif sys.platform == "darwin":
paths = ["/Applications/Tor Browser.app/Contents/MacOS/firefox"]
else:
paths = ["/usr/bin/tor", "/usr/local/bin/tor"]
for path in paths:
if os.path.exists(path):
try:
self.log_signal.emit(f"Starting Tor: {path}")
if sys.platform == "win32":
subprocess.Popen([path], shell=True)
else:
subprocess.Popen([path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
self.log_signal.emit("Waiting for Tor to start (up to 30 seconds)...")
for i in range(30):
time.sleep(1)
self.log_signal.emit(f"Waiting {i+1}/30 sec...")
if self.scanner:
ports = self.scanner.full_scan()
if ports:
self.log_signal.emit(f"Tor started! Found ports: {ports}")
self.finished_signal.emit(True)
return
self.log_signal.emit("Tor started, but ports not found. Try manual scan.")
self.finished_signal.emit(True)
return
except Exception as e:
self.log_signal.emit(f"Start error: {e}")
continue
self.log_signal.emit("Tor Browser not found. Please install it.")
self.finished_signal.emit(False)
class ProcessUpdater(QThread):
processes_signal = pyqtSignal(list)
def run(self):
while True:
processes = []
try:
for proc in psutil.process_iter(['pid', 'name', 'exe']):
try:
name = proc.info['name'] or "Unknown"
exe = proc.info['exe'] or ""
if exe and not exe.lower().endswith('.exe'):
continue
if name.lower() in ['system', 'idle']:
continue
processes.append({'pid': proc.info['pid'], 'name': name, 'exe': exe})
except:
continue
processes.sort(key=lambda x: x['name'].lower())
self.processes_signal.emit(processes)
except:
pass
time.sleep(5)
class TorAppSelector(QMainWindow):
def __init__(self):
super().__init__()
self.scanner = TorPortScanner()
self.selected_port = None
self.processes = []
self.selected_processes = []
self.system_proxy_active = False
self.scanning_in_progress = False
self.updating_processes = False
self.initUI()
self.update_status("Waiting...")
self.process_updater = ProcessUpdater()
self.process_updater.processes_signal.connect(self.update_process_list)
self.process_updater.start()
def initUI(self):
self.setWindowTitle("Tor App Selector v6.3")
self.setGeometry(200, 200, 900, 700)
self.setStyleSheet("""
QMainWindow { background-color: #1e1e2e; }
QLabel { color: #cdd6f4; font-size: 13px; font-weight: bold; }
QPushButton {
background-color: #313244; color: #cdd6f4;
border: 1px solid #45475a; padding: 8px 15px;
border-radius: 6px; font-weight: bold;
}
QPushButton:hover { background-color: #45475a; }
QPushButton#launch_btn {
background-color: #a6e3a1; color: #1e1e2e;
font-size: 14px; padding: 12px;
}
QPushButton#launch_btn:hover { background-color: #89d48a; }
QPushButton#proxy_btn_on {
background-color: #f9e2af; color: #1e1e2e;
}
QPushButton#proxy_btn_on:hover { background-color: #f2d08a; }
QPushButton#proxy_btn_off {
background-color: #f38ba8; color: #1e1e2e;
}
QPushButton#proxy_btn_off:hover { background-color: #e06b87; }
QListWidget {
background-color: #181825; color: #cdd6f4;
border: 1px solid #45475a; border-radius: 4px;
font-family: 'Courier New'; font-size: 12px;
}
QListWidget::item:selected {
background-color: #45475a; color: #a6e3a1;
}
QTextEdit {
background-color: #11111b; color: #89b4fa;
border: 1px solid #45475a; border-radius: 4px;
font-family: 'Courier New';
}
QStatusBar { color: #a6e3a1; }
QProgressBar {
background-color: #181825;
border: 1px solid #45475a;
border-radius: 4px;
color: #cdd6f4;
text-align: center;
}
QProgressBar::chunk {
background-color: #89b4fa;
border-radius: 4px;
}
""")
central = QWidget()
self.setCentralWidget(central)
layout = QVBoxLayout(central)
title = QLabel("Tor App Selector v6.3")
title.setFont(QFont("Arial", 14, QFont.Bold))
title.setStyleSheet("color: #89b4fa; padding: 10px;")
layout.addWidget(title)
top_layout = QHBoxLayout()
self.scan_btn = QPushButton("Scan Tor Ports")
self.scan_btn.clicked.connect(self.start_scan)
self.start_tor_btn = QPushButton("Start Tor")
self.start_tor_btn.clicked.connect(self.launch_tor_with_scan)
self.proxy_btn = QPushButton("Enable System Proxy")
self.proxy_btn.setObjectName("proxy_btn_off")
self.proxy_btn.clicked.connect(self.toggle_system_proxy)
top_layout.addWidget(self.scan_btn)
top_layout.addWidget(self.start_tor_btn)
top_layout.addWidget(self.proxy_btn)
top_layout.addStretch()
layout.addLayout(top_layout)
self.progress_bar = QProgressBar()
self.progress_bar.setVisible(False)
layout.addWidget(self.progress_bar)
info_label = QLabel("Select multiple apps: Ctrl+click or Shift+click")
info_label.setStyleSheet("color: #a6e3a1; font-size: 11px;")
layout.addWidget(info_label)
layout.addWidget(QLabel("Available Tor Ports (select one):"))
self.port_list = QListWidget()
self.port_list.setMaximumHeight(80)
self.port_list.itemClicked.connect(self.on_port_selected)
layout.addWidget(self.port_list)
layout.addWidget(QLabel("Running Applications (select one or more):"))
self.process_list = QListWidget()
self.process_list.setSelectionMode(QListWidget.ExtendedSelection)
self.process_list.setMaximumHeight(350)
self.process_list.itemClicked.connect(self.on_process_selected)
layout.addWidget(self.process_list)
self.launch_btn = QPushButton("LAUNCH SELECTED APPS VIA TOR")
self.launch_btn.setObjectName("launch_btn")
self.launch_btn.clicked.connect(self.launch_selected_apps)
layout.addWidget(self.launch_btn)
layout.addWidget(QLabel("Log:"))
self.log_area = QTextEdit()
self.log_area.setMaximumHeight(120)
self.log_area.setReadOnly(True)
layout.addWidget(self.log_area)
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
def update_status(self, text):
self.statusBar.showMessage(text)
def log(self, text):
self.log_area.append(f"[{time.strftime('%H:%M:%S')}] {text}")
def update_process_list(self, processes):
if self.updating_processes:
return
self.updating_processes = True
selected_pids = []
for item in self.process_list.selectedItems():
pid_match = re.search(r"PID:\s*(\d+)", item.text())
if pid_match:
selected_pids.append(int(pid_match.group(1)))
self.process_list.clear()
self.processes = processes
unique_names = {}
for proc in processes:
name = proc['name']
exe = proc['exe']
pid = proc['pid']
skip_names = ['svchost.exe', 'csrss.exe', 'wininit.exe', 'lsass.exe',
'winlogon.exe', 'services.exe', 'smss.exe', 'spoolsv.exe',
'conhost.exe', 'dwm.exe', 'taskhostw.exe', 'explorer.exe',
'python.exe', 'pythonw.exe', 'cmd.exe', 'powershell.exe']
if name.lower() in skip_names:
continue
if name in unique_names:
unique_names[name] += 1
display_name = f"{name} (PID: {pid})"
else:
unique_names[name] = 1
display_name = f"{name} (PID: {pid})"
if 'chrome' in name.lower() or 'firefox' in name.lower() or 'brave' in name.lower():
display_name = "[Browser] " + display_name
elif 'telegram' in name.lower():
display_name = "[Messenger] " + display_name
elif 'discord' in name.lower():
display_name = "[Game] " + display_name
self.process_list.addItem(display_name)
for i in range(self.process_list.count()):
item = self.process_list.item(i)
pid_match = re.search(r"PID:\s*(\d+)", item.text())
if pid_match:
pid = int(pid_match.group(1))
if pid in selected_pids:
item.setSelected(True)
self.updating_processes = False
def on_process_selected(self, item):
self.selected_processes = []
for i in range(self.process_list.count()):
if self.process_list.item(i).isSelected():
item_text = self.process_list.item(i).text()
pid_match = re.search(r"PID:\s*(\d+)", item_text)
if pid_match:
pid = int(pid_match.group(1))
for proc in self.processes:
if proc['pid'] == pid:
self.selected_processes.append(proc)
break
if self.selected_processes:
names = ", ".join([p['name'] for p in self.selected_processes])
self.log(f"Selected apps: {len(self.selected_processes)} ({names})")
def start_scan(self):
if self.scanning_in_progress:
return
self.log("Starting Tor port scan...")
self.port_list.clear()
self.update_status("Scanning...")
self.scanning_in_progress = True
self.progress_bar.setVisible(True)
self.progress_bar.setRange(0, 0)
self.scan_btn.setEnabled(False)
def update_progress(text):
self.log(text)
QApplication.processEvents()
def scan_thread():
try:
ports = self.scanner.full_scan(progress_callback=update_progress)
self.update_ports_signal.emit(ports)
except Exception as e:
self.log(f"Scan error: {e}")
self.update_ports_signal.emit([])
class UpdateSignal(QObject):
update_signal = pyqtSignal(list)
self.update_signal = UpdateSignal()
self.update_signal.update_signal.connect(self.update_port_list)
self.update_ports_signal = self.update_signal.update_signal
threading.Thread(target=scan_thread, daemon=True).start()
def update_port_list(self, ports):
self.port_list.clear()
if ports:
for p in ports:
self.port_list.addItem(f"Port {p} (SOCKS5) ✓")
self.log(f"✅ Active ports found: {len(ports)}")
self.update_status(f"✅ Found: {len(ports)} ports")
self.selected_port = ports[0]
self.port_list.setCurrentRow(0)
self.log(f"Auto-selected port: {self.selected_port}")
else:
self.port_list.addItem("No active ports found")
self.log("❌ Ports not found. Start Tor Browser and try again.")
self.update_status("❌ No ports")
self.selected_port = None
self.scanning_in_progress = False
self.progress_bar.setVisible(False)
self.scan_btn.setEnabled(True)
def launch_tor_with_scan(self):
self.log("Starting Tor Browser...")
self.scan_btn.setEnabled(False)
self.start_tor_btn.setEnabled(False)
self.tor_thread = TorStarter(self.scanner)
self.tor_thread.log_signal.connect(self.log)
self.tor_thread.finished_signal.connect(self.on_tor_started)
self.tor_thread.start()
self.update_status("Starting Tor...")
def on_tor_started(self, success):
self.scan_btn.setEnabled(True)
self.start_tor_btn.setEnabled(True)
if success:
self.log("Tor Browser started, running scan...")
time.sleep(2)
self.start_scan()
else:
self.log("❌ Failed to start Tor Browser. Check installation.")
self.update_status("❌ Tor not started")
def on_port_selected(self, item):
match = re.search(r"\d+", item.text())
if match:
self.selected_port = int(match.group())
self.log(f"Selected port: {self.selected_port}")
def toggle_system_proxy(self):
if not self.selected_port:
self.log("❌ Select a Tor port first!")
QMessageBox.warning(self, "Error", "Select a Tor port!")
return
if self.system_proxy_active:
self.disable_system_proxy()
else:
self.enable_system_proxy()
def enable_system_proxy(self):
try:
key = winreg.OpenKey(
winreg.HKEY_CURRENT_USER,
r"Software\Microsoft\Windows\CurrentVersion\Internet Settings",
0, winreg.KEY_SET_VALUE
)
winreg.SetValueEx(key, "ProxyEnable", 0, winreg.REG_DWORD, 1)
winreg.SetValueEx(key, "ProxyServer", 0, winreg.REG_SZ, f"socks5=127.0.0.1:{self.selected_port}")
winreg.SetValueEx(key, "ProxyOverride", 0, winreg.REG_SZ, "localhost;127.0.0.1;::1")
winreg.CloseKey(key)
ctypes.windll.wininet.InternetSetOptionW(0, 39, 0, 0)
ctypes.windll.wininet.InternetSetOptionW(0, 37, 0, 0)
self.system_proxy_active = True
self.proxy_btn.setText(f"Disable System Proxy (port {self.selected_port})")
self.proxy_btn.setObjectName("proxy_btn_on")
self.proxy_btn.setStyleSheet(self.styleSheet())
self.log(f"✅ SYSTEM PROXY ENABLED! All traffic via Tor (port {self.selected_port})")
self.update_status(f"System proxy active (port {self.selected_port})")
QMessageBox.information(
self, "System Proxy Enabled!",
f"ALL applications now go through Tor (port {self.selected_port})\n\n"
"WARNING:\n- Internet speed will decrease\n- Some apps may not work\n"
"- Click 'Disable System Proxy' to revert"
)
except Exception as e:
self.log(f"❌ Error enabling proxy: {e}")
def disable_system_proxy(self):
try:
key = winreg.OpenKey(
winreg.HKEY_CURRENT_USER,
r"Software\Microsoft\Windows\CurrentVersion\Internet Settings",
0, winreg.KEY_SET_VALUE
)
winreg.SetValueEx(key, "ProxyEnable", 0, winreg.REG_DWORD, 0)
winreg.CloseKey(key)
ctypes.windll.wininet.InternetSetOptionW(0, 39, 0, 0)
ctypes.windll.wininet.InternetSetOptionW(0, 37, 0, 0)
self.system_proxy_active = False
self.proxy_btn.setText("Enable System Proxy")
self.proxy_btn.setObjectName("proxy_btn_off")
self.proxy_btn.setStyleSheet(self.styleSheet())
self.log("✅ SYSTEM PROXY DISABLED")
self.update_status("System proxy disabled")
except Exception as e:
self.log(f"❌ Error disabling proxy: {e}")
def launch_selected_apps(self):
if not self.selected_port:
self.log("❌ Select a port from the list first!")
QMessageBox.warning(self, "Error", "Select a Tor port!")
return
if not self.selected_processes:
self.log("❌ Select at least one application from the list!")
QMessageBox.warning(self, "Error", "Select application(s) from the list!")
return
reply = QMessageBox.question(
self, "Close Old Processes?",
f"Found {len(self.selected_processes)} application(s).\n\n"
"Close their current instances before launching via Tor?",
QMessageBox.Yes | QMessageBox.No
)
close_old = (reply == QMessageBox.Yes)
launched = 0
errors = []
for proc_data in self.selected_processes:
app_name = proc_data['name']
app_path = proc_data['exe']
pid = proc_data['pid']
if not app_path or not os.path.exists(app_path):
errors.append(f"{app_name}: file not found")
continue
self.log(f"Launching {app_name} via Tor (port {self.selected_port})...")
if close_old:
try:
proc = psutil.Process(pid)
proc.terminate()
proc.wait(timeout=3)
self.log(f"Closed old process {app_name} (PID: {pid})")
except:
pass
cmd = [app_path]
env = os.environ.copy()
if any(x in app_path.lower() for x in ['chrome', 'brave', 'chromium']):
cmd.extend([
f"--proxy-server=socks5://127.0.0.1:{self.selected_port}",
"--host-resolver-rules=MAP * ~NOTFOUND , EXCLUDE localhost",
"--new-window",
"https://check.torproject.org"
])
elif 'firefox' in app_path.lower():
profile_dir = os.path.join(os.environ['TEMP'], f"tor_profile_{int(time.time())}_{app_name}")
cmd.extend([
"-CreateProfile", f"TorProfile_{app_name} {profile_dir}",
"-P", f"TorProfile_{app_name}",
"-no-remote", "-new-window",
"https://check.torproject.org"
])
env['http_proxy'] = f'socks5://127.0.0.1:{self.selected_port}'
env['https_proxy'] = f'socks5://127.0.0.1:{self.selected_port}'
else:
self.log(f" {app_name} is not a browser. Use system proxy for it.")
try:
if 'firefox' in app_path.lower():
subprocess.Popen(cmd, env=env, shell=False)
else:
subprocess.Popen(cmd, shell=False)
launched += 1
self.log(f"✅ {app_name} launched")
except Exception as e:
errors.append(f"{app_name}: {e}")
if launched > 0:
self.update_status(f"Launched apps: {launched} via Tor")
self.log(f"✅ Successfully launched {launched} of {len(self.selected_processes)} apps")
if errors:
for err in errors:
self.log(f"❌ {err}")
QMessageBox.warning(self, "Partial Success",
f"Launched: {launched}\nErrors: {len(errors)}\n\n" + "\n".join(errors[:5]))
elif launched > 0:
QMessageBox.information(self, "Success!",
f"✅ All {launched} app(s) launched via Tor (port {self.selected_port})")
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setStyle('Fusion')
window = TorAppSelector()
window.show()
sys.exit(app.exec_())
📦 Requirements + how to run
Install Python deps:
pip install psutil PyQt5
Also required: Tor Browser installed (the standard free version — that’s all)
Lighter alternative: don’t want the browser running in the background? Use the Tor Expert Bundle — just tor.exe, no GUI. Pair with NSSM to install it as a Windows service that starts on boot.
Run:
python tor_app_selector.py
Steps:
- Open Tor Browser and let it connect to the network
- Run the script → click Scan Tor Ports (auto-finds port 9150)
- Choose your mode:
- System-wide: click Enable System Proxy → all traffic routes through Tor
- Per-app: Ctrl+click apps in the list → Launch Selected Apps via Tor
- Verify at check.torproject.org

✅ Proof it works
check.torproject.org confirms the connection — and doesn’t expose that a proxy is in use.
Speed through Tor is surprisingly usable. Not the crawl most people expect.
🔗 Go deeper — fixes, tools & the full rabbit hole
Verify your connection first
Before trusting any proxy setup — check for leaks:
- DNS Leak Test — are your DNS queries bypassing Tor?
- IPLeak.net — IP address, DNS, and WebRTC in one test
- BrowserLeaks WebRTC — Chrome/Firefox can leak your real IP via WebRTC even through SOCKS5
- BrowserLeaks DNS — resolves 50 random domains to show which DNS server actually answers
· · · · · · · · · · · · · · · ·
Route games, Telegram, Discord (they ignore WinInet)
These apps use raw TCP/UDP that bypasses the Windows system proxy entirely. Two solutions:
- Netch / releases — per-process proxy using WinDivert; routes any EXE through SOCKS5 at the packet level, no system-wide setting
- tun2socks — creates a virtual TUN adapter and routes ALL traffic through Tor’s SOCKS5; apps can’t bypass it
- proxychains-windows — Winsock hook approach; injects into the target process and redirects connect() calls; no kernel driver needed
- ProxiFyre / releases — per-app SOCKS5 proxifier using NDISAPI; routes TCP + UDP
· · · · · · · · · · · · · · · ·
Run Tor without the browser (lighter setup)
- Tor Expert Bundle — official standalone
tor.exe(no browser, ~10MB) - Expert Bundle v15.0.18 direct download — Windows x86_64
- NSSM — Non-Sucking Service Manager; wraps tor.exe as a persistent Windows service
- matinrco/tor — pre-configured Expert Bundle for Windows with VBS launcher, SOCKS5 on 9050, no browser
- SuperUser: tor.exe as Windows service — using Tor’s built-in
--service installflag (no NSSM needed) - Sample torrc gist — SocksPort 9050, ControlPort 9051, CookieAuthentication, DataDirectory, pluggable transport lines
· · · · · · · · · · · · · · · ·
Add exit country switching right now (don’t wait for v7)
The exit country feature is already built into Tor — you just need Python’s stem library to control it:
- stem / PyPI — official Python Tor controller (
pip install stem) - stem tutorial: ExitNodes selection — pick exit country via
NEWNYM+ExitNodes {US}in 5 lines - stem API: Controller class — full NEWNYM, signal, circuit, stream methods
- torrc man page —
IsolateDestAddr,IsolateSOCKSAuth, multi-SocksPort for per-app circuit isolation - Tor Control Protocol spec — NEWNYM, MAPADDRESS, ATTACHSTREAM, EXTENDCIRCUIT reference
· · · · · · · · · · · · · · · ·
The tech inside this tool
- basil00/Tallow — transparent Tor for Windows via WinDivert; the packet-level reference implementation of what this tool does at the registry level
- basil00/WinDivert — the kernel driver powering Netch, Tallow, GoodbyeDPI, and most Windows transparent proxifiers
- ValdikSS/GoodbyeDPI — shows WinDivert NETWORK_LAYER per-packet filtering and manipulation patterns
- WinDivert API docs — full programming reference for WinDivertOpen, filters, WINDIVERT_LAYER
· · · · · · · · · · · · · · · ·
Heavier alternatives (if you need everything routed, reliably)
- sing-box / releases — universal proxy platform; TUN inbound + SOCKS5 outbound; routes games, Discord, everything
- Clash Verge Rev / releases — GUI for mihomo; TUN mode toggle; Windows installer; point SOCKS5 outbound at port 9150
- sing-box TUN docs —
auto_route,strict_route, stack options
· · · · · · · · · · · · · · · ·
Bypass DPI — when Tor itself is blocked
Standard Tor traffic gets fingerprinted and killed by corporate/ISP DPI. Pluggable transports make it look like HTTPS:
- Expert Bundle dist index — the bundle already includes
lyrebird.exe(obfs4),snowflake.exe,meek_client.exeas standalone binaries - obfs4 source repo — obfuscated Tor transport; add
ClientTransportPlugin obfs4 exec /path/lyrebird.exeto torrc - Snowflake — WebRTC-based Tor bridge; bypasses DPI that targets Tor’s TLS fingerprint
- Pluggable Transports spec — the IPC protocol any PT binary implements
· · · · · · · · · · · · · · · ·
Other anonymity networks — same SOCKS5 interface, different network
This tool’s SOCKS5 port scan works with any anonymity daemon, not just Tor:
- i2pd / releases — C++ I2P router; SOCKS5 proxy on port 4447, HTTP proxy on 4444; runs as Windows service
- geti2p.net — Java I2P router; Windows installer with built-in browser config
- Lokinet / releases — creates a virtual network adapter on Windows; onion-routed at the IP layer
- Yggdrasil — end-to-end encrypted mesh network; Windows MSI installer
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
Tor was already running on your machine. This just makes everything else use it.




!