Files
Justin Oros f5be6d53b2 PoGoMover
WebApp for spoofing your location on PoGo (Proof-Of-Concept)
2026-05-25 15:50:52 -07:00

417 lines
15 KiB
Python

import os
import sys
import time
import platform
import subprocess
import webbrowser
import threading
def banner(msg, char="="):
print(f"\n{char * 50}")
print(f" {msg}")
print(f"{char * 50}")
def step(msg):
print(f"\n▶ {msg}")
def ok(msg):
print(f" ✓ {msg}")
def warn(msg):
print(f" ⚠ {msg}")
def fail(msg):
print(f" ✗ {msg}")
def check_macos():
if platform.system() != "Darwin":
fail("PoGo Mover requires macOS.")
sys.exit(1)
ok("macOS detected")
def check_python():
if sys.version_info < (3, 8):
fail("Python 3.8 or newer is required.")
sys.exit(1)
ok(f"Python {sys.version.split()[0]}")
def install_pymobiledevice3():
step("Checking for pymobiledevice3...")
try:
import pymobiledevice3
ok("pymobiledevice3 already installed")
return
except ImportError:
pass
warn("pymobiledevice3 not found — installing now (this may take a minute)...")
result = subprocess.run(
[sys.executable, "-m", "pip", "install", "pymobiledevice3", "--quiet"],
capture_output=False
)
if result.returncode != 0:
fail("Installation failed. Try running: pip3 install pymobiledevice3")
sys.exit(1)
ok("pymobiledevice3 installed")
def detect_iphone_system_profiler():
try:
result = subprocess.run(
["system_profiler", "SPUSBDataType", "-json"],
capture_output=True, text=True, timeout=10
)
if result.returncode == 0 and ("iPhone" in result.stdout or "iPad" in result.stdout):
return True
except Exception:
pass
return False
def detect_iphone_ioreg():
try:
result = subprocess.run(
["ioreg", "-p", "IOUSB", "-l", "-w", "0"],
capture_output=True, text=True, timeout=10
)
if result.returncode == 0 and "iPhone" in result.stdout:
return True
except Exception:
pass
return False
def detect_iphone_pymobiledevice():
try:
result = subprocess.run(
["pymobiledevice3", "list-devices"],
capture_output=True, text=True, timeout=10
)
output = result.stdout.strip()
if output and len(output) > 8:
return True
except Exception:
pass
try:
result = subprocess.run(
["pymobiledevice3", "usbmux", "list"],
capture_output=True, text=True, timeout=10
)
output = result.stdout.strip()
if output and len(output) > 8:
return True
except Exception:
pass
return False
def check_iphone():
step("Checking for connected iPhone...")
if detect_iphone_system_profiler() or detect_iphone_ioreg():
ok("iPhone detected via USB")
return True
if detect_iphone_pymobiledevice():
ok("iPhone detected via pymobiledevice3")
return True
warn("iPhone not detected via USB.")
print()
print(" Things to try:")
print(" 1. Make sure the USB cable is fully plugged in")
print(" 2. Unlock your iPhone and tap 'Trust' if prompted")
print(" 3. Try a different USB cable or port")
print(" 4. Open Finder — does your iPhone appear in the sidebar?")
print()
choice = input(" Press Enter to retry, S to skip this check, or Ctrl+C to quit: ").strip().lower()
if choice == "s":
warn("Skipping iPhone check — continuing anyway.")
return False
return check_iphone()
def get_ios_version_from_ioreg():
try:
result = subprocess.run(
["ioreg", "-p", "IOUSB", "-l", "-w", "0"],
capture_output=True, text=True, timeout=10
)
for line in result.stdout.splitlines():
if "ProductVersion" in line:
parts = line.split('"')
for i, p in enumerate(parts):
if p == "ProductVersion" and i + 2 < len(parts):
version_str = parts[i + 2]
return int(version_str.split(".")[0])
except Exception:
pass
return 0
def get_ios_version_from_pymobiledevice():
try:
import json
for cmd in [
["pymobiledevice3", "list-devices", "--json"],
["pymobiledevice3", "usbmux", "list", "--json"],
]:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=8)
try:
devices = json.loads(result.stdout)
if isinstance(devices, list) and devices:
v = devices[0].get("ProductVersion") or devices[0].get("product_version", "0")
return int(str(v).split(".")[0])
if isinstance(devices, dict):
for v in ["ProductVersion", "product_version"]:
if v in devices:
return int(str(devices[v]).split(".")[0])
except Exception:
pass
except Exception:
pass
return 0
def get_ios_version():
v = get_ios_version_from_pymobiledevice()
if v > 0:
return v
return get_ios_version_from_ioreg()
def maybe_start_tunnel():
step("Starting GPS tunnel...")
ios = get_ios_version()
if ios == 0:
ios = 17
if ios < 17:
ok(f"iOS {ios} detected — no tunnel needed.")
return None
tunnel_cmd = ["sudo", "pymobiledevice3", "remote", "tunneld"]
warn("The tunnel requires your Mac password (sudo).")
print()
proc = subprocess.Popen(
tunnel_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True
)
deadline = time.time() + 30
tunnel_ready = False
while time.time() < deadline:
line = proc.stdout.readline()
if not line:
if proc.poll() is not None:
break
time.sleep(0.1)
continue
line = line.strip()
if "Application startup complete" in line or "Uvicorn running" in line:
tunnel_ready = True
break
if "password" in line.lower() or "Password" in line or "ERROR" in line.upper():
print(f" {line}")
if proc.poll() is not None:
fail("Tunnel process exited unexpectedly.")
warn("Try running manually in a separate tab:")
warn(" sudo pymobiledevice3 remote tunneld")
input(" Press Enter once the tunnel is running, or Ctrl+C to quit...")
return None
if tunnel_ready:
ok("Tunnel ready — tunneld HTTP service is running")
else:
ok("Tunnel started (waiting for device connection...)")
threading.Thread(target=lambda: _drain_tunnel(proc), daemon=True).start()
return proc
def _drain_tunnel(proc):
try:
for line in proc.stdout:
pass
except Exception:
pass
def check_xcode():
try:
result = subprocess.run(
["xcode-select", "-p"],
capture_output=True, text=True, timeout=5
)
if result.returncode == 0 and result.stdout.strip():
path = result.stdout.strip()
if "Xcode.app" in path:
ok(f"Xcode installed at {path}")
return "xcode"
else:
warn("Only Command Line Tools found — Xcode app is needed for Developer Mode")
return "clt_only"
except Exception:
pass
warn("Xcode not found")
return "none"
def check_developer_mode():
try:
result = subprocess.run(
["pymobiledevice3", "amfi", "developer-mode-status"],
capture_output=True, text=True, timeout=8
)
status = result.stdout.strip().lower()
if "true" in status:
ok("Developer Mode is ON ✓")
return True
elif "false" in status:
return False
else:
return None
except Exception:
return None
def check_and_guide_developer_mode():
step("Checking Developer Mode status on iPhone...")
dev_mode = check_developer_mode()
if dev_mode is True:
return
if dev_mode is False:
fail("Developer Mode is OFF — GPS spoofing will not work until this is enabled.")
else:
warn("Could not determine Developer Mode status.")
print()
xcode_status = check_xcode()
print()
if xcode_status == "xcode":
print(" ┌─────────────────────────────────────────────────┐")
print(" │ HOW TO ENABLE DEVELOPER MODE (Xcode found) │")
print(" ├─────────────────────────────────────────────────┤")
print(" │ 1. Open Xcode → create or open any project │")
print(" │ 2. Menu: Window → Devices and Simulators │")
print(" │ (this activates the iPhone connection) │")
print(" │ 3. On iPhone: Settings → Privacy & Security │")
print(" │ → scroll to bottom → Developer Mode → ON │")
print(" │ 4. iPhone will restart automatically │")
print(" │ 5. After restart: Swipe Up and enter passcode │")
print(" │ to confirm Developer Mode │")
print(" │ 6. Come back here and rerun start.py │")
print(" └─────────────────────────────────────────────────┘")
elif xcode_status == "clt_only":
print(" ┌─────────────────────────────────────────────────┐")
print(" │ HOW TO ENABLE DEVELOPER MODE │")
print(" ├─────────────────────────────────────────────────┤")
print(" │ Command Line Tools found but Xcode app needed. │")
print(" │ │")
print(" │ Option A — Install Xcode (recommended): │")
print(" │ 1. Open Mac App Store → search 'Xcode' │")
print(" │ 2. Install (free, ~10GB) │")
print(" │ 3. Open Xcode → Window → Devices │")
print(" │ 4. Click iPhone → Enable Developer Mode │")
print(" │ │")
print(" │ Option B — Try without Xcode: │")
print(" │ On iPhone: Settings → Privacy & Security │")
print(" │ → scroll to bottom → Developer Mode → ON │")
print(" │ (only appears after connecting to Xcode once) │")
print(" └─────────────────────────────────────────────────┘")
else:
print(" ┌─────────────────────────────────────────────────┐")
print(" │ HOW TO ENABLE DEVELOPER MODE (no Xcode found) │")
print(" ├─────────────────────────────────────────────────┤")
print(" │ Option A — Install Xcode (recommended): │")
print(" │ 1. Open Mac App Store → search 'Xcode' │")
print(" │ 2. Install (free, ~10GB) │")
print(" │ 3. Open Xcode → Window → Devices │")
print(" │ 4. Click iPhone → Enable Developer Mode │")
print(" │ 5. Confirm on iPhone → restart │")
print(" │ │")
print(" │ Option B — Apple Configurator 2 (tiny, free): │")
print(" │ 1. Mac App Store → 'Apple Configurator 2' │")
print(" │ 2. Open it with iPhone connected │")
print(" │ 3. Actions → Advanced → Enable Developer Mode │")
print(" │ │")
print(" │ Option C — Apple Store: │")
print(" │ Ask staff to enable Developer Mode — free │")
print(" │ and takes 2 minutes with their tools │")
print(" └─────────────────────────────────────────────────┘")
print()
if dev_mode is False:
choice = input(" Press Enter to continue anyway (GPS won't work until fixed), or Ctrl+C to quit: ").strip()
else:
ok("Continuing — Developer Mode status unknown, GPS may still work.")
step("Mounting developer disk image (if needed)...")
try:
result = subprocess.run(
["pymobiledevice3", "mounter", "auto-mount"],
capture_output=True, text=True, timeout=30
)
if result.returncode == 0:
ok("Developer disk image ready")
else:
warn("Mount step returned non-zero — likely already mounted, continuing.")
except Exception as e:
warn(f"Mount step skipped: {e}")
def mount_developer_image():
step("Mounting developer disk image (if needed)...")
try:
result = subprocess.run(
["pymobiledevice3", "mounter", "auto-mount"],
capture_output=True, text=True, timeout=30
)
if result.returncode == 0:
ok("Developer disk image ready")
else:
ok("Developer disk image already mounted")
except Exception as e:
warn(f"Mount step skipped: {e}")
def open_browser():
url = "http://localhost:7777"
step("Opening PoGo Mover in your browser...")
time.sleep(1.5)
webbrowser.open(url)
ok(f"Opened: {url}")
def start_server():
server_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "server.py")
step("Starting GPS server on http://localhost:7777...")
ok("Server running — press Ctrl+C to stop.")
print()
try:
subprocess.run([sys.executable, server_path])
except KeyboardInterrupt:
pass
def main():
banner("PoGo Mover — Pokémon GO GPS Controller", "=")
print(" Setting everything up automatically...\n")
check_macos()
check_python()
install_pymobiledevice3()
check_iphone()
check_and_guide_developer_mode()
tunnel_proc = maybe_start_tunnel()
mount_developer_image()
banner("All set! Launching PoGo Mover", "-")
threading.Thread(target=open_browser, daemon=True).start()
start_server()
if tunnel_proc and tunnel_proc.poll() is None:
tunnel_proc.terminate()
tunnel_proc.wait()
if __name__ == "__main__":
main()