PoGoMover
WebApp for spoofing your location on PoGo (Proof-Of-Concept)
This commit is contained in:
@@ -0,0 +1,416 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user