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.




!