Add 'unsupported' homebrew support & 'XeUnshackle'
This commit is contained in:
@@ -9,7 +9,6 @@ using Windows.Win32.Storage.FileSystem;
|
||||
using static Windows.Win32.PInvoke;
|
||||
using static BadBuilder.Formatter.Constants;
|
||||
using static BadBuilder.Formatter.Utilities;
|
||||
using Windows.Win32.Foundation;
|
||||
|
||||
namespace BadBuilder.Formatter
|
||||
{
|
||||
@@ -17,7 +16,7 @@ namespace BadBuilder.Formatter
|
||||
{
|
||||
public static unsafe string FormatVolume(char driveLetter, long diskSize)
|
||||
{
|
||||
if (diskSize < 32 * GB)
|
||||
if (diskSize < 31 * GB) // Just a safeguard to ensure that we never run into close calls with disk size.
|
||||
{
|
||||
Process process = new Process
|
||||
{
|
||||
|
||||
@@ -33,18 +33,15 @@ namespace BadBuilder
|
||||
);
|
||||
}
|
||||
|
||||
static bool FormatDisk(List<DiskInfo> disks, string selectedDisk)
|
||||
static bool FormatDisk(DiskInfo disk)
|
||||
{
|
||||
int diskIndex = disks.FindIndex(disk => $"{disk.DriveLetter} ({disk.SizeFormatted}) - {disk.Type}" == selectedDisk);
|
||||
bool ret = true;
|
||||
string output = string.Empty;
|
||||
|
||||
AnsiConsole.Status().SpinnerStyle(LightOrangeStyle).Start($"[#76B900]Formatting disk[/] {selectedDisk}", async ctx =>
|
||||
AnsiConsole.Status().SpinnerStyle(LightOrangeStyle).Start($"[#76B900]Formatting disk[/] {disk.DriveLetter} ({disk.SizeFormatted}) - {disk.Type}", async ctx =>
|
||||
{
|
||||
if (diskIndex == -1) return;
|
||||
|
||||
ClearConsole();
|
||||
output = DiskHelper.FormatDisk(disks[diskIndex]);
|
||||
output = DiskHelper.FormatDisk(disk);
|
||||
if (output != string.Empty) ret = false;
|
||||
});
|
||||
|
||||
|
||||
@@ -24,9 +24,6 @@ namespace BadBuilder
|
||||
await ArchiveHelper.ExtractFileAsync(item.name, item.path, task);
|
||||
}));
|
||||
});
|
||||
|
||||
string status = "[+]";
|
||||
AnsiConsole.MarkupInterpolated($"[#76B900]{status}[/] [bold]{filesToExtract.Count()}[/] files extracted.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace BadBuilder
|
||||
);
|
||||
}
|
||||
|
||||
public static List<HomebrewApp> ManageHomebrewApps()
|
||||
internal static List<HomebrewApp> ManageHomebrewApps()
|
||||
{
|
||||
var homebrewApps = new List<HomebrewApp>();
|
||||
|
||||
@@ -37,11 +37,7 @@ namespace BadBuilder
|
||||
|
||||
var newApp = AddHomebrewApp();
|
||||
if (newApp != null)
|
||||
{
|
||||
homebrewApps.Add(newApp.Value);
|
||||
AnsiConsole.Status()
|
||||
.Start("Adding...", ctx => ctx.Spinner(Spinner.Known.Dots2));
|
||||
}
|
||||
break;
|
||||
|
||||
case "View Added Apps":
|
||||
@@ -85,31 +81,30 @@ namespace BadBuilder
|
||||
string folderPath = AnsiConsole.Ask<string>("[#FFA500]Enter the folder path for the app:[/]");
|
||||
if (!Directory.Exists(folderPath))
|
||||
{
|
||||
AnsiConsole.MarkupLine("[#ffac4d]Invalid folder path. Please try again.[/]");
|
||||
AnsiConsole.MarkupLine("[#ffac4d]Invalid folder path. Please try again.\n[/]");
|
||||
return null;
|
||||
}
|
||||
|
||||
string[] xexFiles = Directory.GetFiles(folderPath, "*.xex");
|
||||
if (xexFiles.Length == 0)
|
||||
{
|
||||
AnsiConsole.MarkupLine("[#ffac4d]No XEX files found in this folder.[/]");
|
||||
return null;
|
||||
}
|
||||
|
||||
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
#pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint.
|
||||
string entryPoint = xexFiles.Length switch
|
||||
{
|
||||
0 => AnsiConsole.Prompt(
|
||||
new TextPrompt<string>("[#ffac4d]No .xex files found.[/] Enter entry point:")
|
||||
.Validate(path => File.Exists(path) ? ValidationResult.Success() : ValidationResult.Error("File not found"))
|
||||
),
|
||||
new TextPrompt<string>("[grey]No .xex files found in this folder.[/] [#FFA500]Enter the path to the entry point:[/]")
|
||||
.Validate(path => File.Exists(path.Trim().Trim('"')) && Path.GetExtension(path.Trim().Trim('"')) == ".xex" ? ValidationResult.Success() : ValidationResult.Error("[#ffac4d]File not found or is not an XEX file.[/]\n"))
|
||||
).Trim().Trim('"'),
|
||||
1 => xexFiles[0],
|
||||
_ => AnsiConsole.Prompt(
|
||||
new SelectionPrompt<string>()
|
||||
new SelectionPrompt<string?>()
|
||||
.Title("[#FFA500]Select entry point:[/]")
|
||||
.HighlightStyle(PeachStyle)
|
||||
.AddChoices(xexFiles.Select(Path.GetFileName))
|
||||
)
|
||||
};
|
||||
#pragma warning restore CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint.
|
||||
#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type.
|
||||
|
||||
ClearConsole();
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace BadBuilder.Helpers
|
||||
{
|
||||
internal static class DiskHelper
|
||||
{
|
||||
public static List<DiskInfo> GetDisks()
|
||||
internal static List<DiskInfo> GetDisks()
|
||||
{
|
||||
var disks = new List<DiskInfo>();
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace BadBuilder.Helpers
|
||||
List<string> repos =
|
||||
[
|
||||
"grimdoomer/Xbox360BadUpdate",
|
||||
"Byrom90/XeUnshackle",
|
||||
"FreeMyXe/FreeMyXe"
|
||||
];
|
||||
|
||||
@@ -28,6 +29,7 @@ namespace BadBuilder.Helpers
|
||||
var name when name.Contains("Free", StringComparison.OrdinalIgnoreCase) => "FreeMyXe",
|
||||
var name when name.Contains("Tools", StringComparison.OrdinalIgnoreCase) => "BadUpdate Tools",
|
||||
var name when name.Contains("BadUpdate", StringComparison.OrdinalIgnoreCase) => "BadUpdate",
|
||||
var name when name.Contains("XeUnshackle", StringComparison.OrdinalIgnoreCase) => "XeUnshackle",
|
||||
_ => asset.Name.Substring(0, asset.Name.Length - 4)
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using Spectre.Console;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BadBuilder.Helpers
|
||||
{
|
||||
@@ -12,8 +13,8 @@ namespace BadBuilder.Helpers
|
||||
{
|
||||
FileName = xexToolPath,
|
||||
Arguments = $"-m r -r a \"{xexPath}\"",
|
||||
RedirectStandardOutput = false,
|
||||
RedirectStandardError = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
@@ -21,6 +22,13 @@ namespace BadBuilder.Helpers
|
||||
|
||||
process.Start();
|
||||
await process.WaitForExitAsync();
|
||||
|
||||
if (process.ExitCode != 0)
|
||||
{
|
||||
string status = "[-]";
|
||||
AnsiConsole.MarkupLineInterpolated($"\n[#FF7200]{status}[/] The program {Path.GetFileNameWithoutExtension(xexPath)} was unable to be patched. XexTool output:");
|
||||
Console.WriteLine(process.StandardError.ReadToEnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,8 @@ namespace BadBuilder
|
||||
|
||||
static ActionQueue actionQueue = new();
|
||||
|
||||
static DiskInfo targetDisk = new("Z:\\", "Fixed", 0, "", 0, int.MaxValue); // Default values just incase.
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
ShowWelcomeMessage();
|
||||
@@ -40,10 +42,13 @@ namespace BadBuilder
|
||||
string selectedDisk = PromptDiskSelection(disks);
|
||||
TargetDriveLetter = selectedDisk.Substring(0, 3);
|
||||
|
||||
int diskIndex = disks.FindIndex(disk => $"{disk.DriveLetter} ({disk.SizeFormatted}) - {disk.Type}" == selectedDisk);
|
||||
targetDisk = disks[diskIndex];
|
||||
|
||||
bool confirmation = PromptFormatConfirmation(selectedDisk);
|
||||
if (confirmation)
|
||||
{
|
||||
if (!FormatDisk(disks, selectedDisk)) continue;
|
||||
if (!FormatDisk(targetDisk)) continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -51,13 +56,21 @@ namespace BadBuilder
|
||||
List<ArchiveItem> downloadedFiles = DownloadRequiredFiles().Result;
|
||||
ExtractFiles(downloadedFiles).Wait();
|
||||
|
||||
ClearConsole();
|
||||
string selectedDefaultApp = AnsiConsole.Prompt(
|
||||
new SelectionPrompt<string>()
|
||||
.Title("Which program should be launched by BadUpdate?")
|
||||
.HighlightStyle(GreenStyle)
|
||||
.AddChoices(
|
||||
"FreeMyXe",
|
||||
"XeUnshackle"
|
||||
)
|
||||
);
|
||||
|
||||
AnsiConsole.MarkupLine("\n\n[#76B900]{0}[/] Copying requried files and folders.", Markup.Escape("[*]"));
|
||||
AnsiConsole.MarkupLine("[#76B900]{0}[/] Copying requried files and folders.", Markup.Escape("[*]"));
|
||||
foreach (var folder in Directory.GetDirectories($@"{EXTRACTED_DIR}"))
|
||||
{
|
||||
var folderName = folder.Split("\\").Last();
|
||||
|
||||
switch (folderName)
|
||||
switch (folder.Split("\\").Last())
|
||||
{
|
||||
case "XEXMenu":
|
||||
EnqueueMirrorDirectory(
|
||||
@@ -68,6 +81,7 @@ namespace BadBuilder
|
||||
break;
|
||||
|
||||
case "FreeMyXe":
|
||||
if (selectedDefaultApp != "FreeMyXe") break;
|
||||
EnqueueFileCopy(
|
||||
Path.Combine(folder, "FreeMyXe.xex"),
|
||||
Path.Combine(TargetDriveLetter, "BadUpdatePayload", "default.xex"),
|
||||
@@ -75,6 +89,17 @@ namespace BadBuilder
|
||||
);
|
||||
break;
|
||||
|
||||
case "XeUnshackle":
|
||||
if (selectedDefaultApp != "XeUnshackle") break;
|
||||
string subFolderPath = Directory.GetDirectories(folder).FirstOrDefault();
|
||||
File.Delete(Path.Combine(subFolderPath, "README - IMPORTANT.txt"));
|
||||
EnqueueMirrorDirectory(
|
||||
subFolderPath,
|
||||
TargetDriveLetter,
|
||||
9
|
||||
);
|
||||
break;
|
||||
|
||||
case "BadUpdate":
|
||||
actionQueue.EnqueueAction(async () =>
|
||||
{
|
||||
@@ -82,7 +107,7 @@ namespace BadBuilder
|
||||
writer.WriteLine("USB Storage Device");
|
||||
|
||||
using (StreamWriter writer = new(Path.Combine(TargetDriveLetter, "info.txt")))
|
||||
writer.WriteLine("This drive was created with BadBuilder by Pdawg.\nFind more info here: https://github.com/Pdawg-bytes/BadBuilder");
|
||||
writer.WriteLine($"This drive was created with BadBuilder by Pdawg.\nFind more info here: https://github.com/Pdawg-bytes/BadBuilder\nConfiguration: \n- BadUpdate target binary: {selectedDefaultApp}");
|
||||
|
||||
Directory.CreateDirectory(Path.Combine(TargetDriveLetter, "Apps"));
|
||||
await FileSystemHelper.MirrorDirectoryAsync(Path.Combine(folder, "Rock Band Blitz"), TargetDriveLetter);
|
||||
@@ -109,14 +134,18 @@ namespace BadBuilder
|
||||
}, 6);
|
||||
break;
|
||||
|
||||
default: throw new Exception($"Unexpected directory in working folder: {folder}");
|
||||
default: throw new Exception($"[-] Unexpected directory in working folder: {folder}");
|
||||
}
|
||||
}
|
||||
actionQueue.ExecuteActionsAsync().Wait();
|
||||
|
||||
File.AppendAllText(Path.Combine(TargetDriveLetter, "info.txt"), $"- Disk formatted using {(targetDisk.TotalSize < 31 * GB ? "Windows \"format.com\"" : "BadBuilder Large FAT32 formatter")}\n");
|
||||
File.AppendAllText(Path.Combine(TargetDriveLetter, "info.txt"), $"- Disk total size: {targetDisk.TotalSize} bytes\n");
|
||||
|
||||
ClearConsole();
|
||||
if (!PromptAddHomebrew())
|
||||
{
|
||||
WriteHomebrewLog(1);
|
||||
AnsiConsole.MarkupLine("\n[#76B900]{0}[/] Your USB drive is ready to go.", Markup.Escape("[+]"));
|
||||
Console.Write("\nPress any key to exit...");
|
||||
Console.ReadKey();
|
||||
@@ -134,12 +163,14 @@ namespace BadBuilder
|
||||
await Task.WhenAll(homebrewApps.Select(async item =>
|
||||
{
|
||||
await FileSystemHelper.MirrorDirectoryAsync(item.folder, Path.Combine(TargetDriveLetter, "Apps", item.name));
|
||||
await PatchHelper.PatchXexAsync(Path.Combine(TargetDriveLetter, "Apps", item.name, Path.GetFileName(item.entryPoint)), XexToolPath);
|
||||
await PatchHelper.PatchXexAsync(item.entryPoint, XexToolPath);
|
||||
}));
|
||||
}).Wait();
|
||||
|
||||
WriteHomebrewLog(homebrewApps.Count + 1);
|
||||
|
||||
string status = "[+]";
|
||||
AnsiConsole.MarkupInterpolated($"\n[#76B900]{status}[/] [bold]{homebrewApps.Count()}[/] apps copied.\n");
|
||||
AnsiConsole.MarkupLineInterpolated($"\n[#76B900]{status}[/] [bold]{homebrewApps.Count}[/] apps copied.");
|
||||
|
||||
AnsiConsole.MarkupLine("\n[#76B900]{0}[/] Your USB drive is ready to go.", Markup.Escape("[+]"));
|
||||
|
||||
@@ -163,6 +194,13 @@ namespace BadBuilder
|
||||
}, priority);
|
||||
}
|
||||
|
||||
static void WriteHomebrewLog(int count)
|
||||
{
|
||||
string logPath = Path.Combine(TargetDriveLetter, "info.txt");
|
||||
string logEntry = $"- {count} homebrew app(s) added (including Simple 360 NAND Flasher)\n";
|
||||
File.AppendAllText(logPath, logEntry);
|
||||
}
|
||||
|
||||
|
||||
static void ShowWelcomeMessage() => AnsiConsole.Markup(
|
||||
"""
|
||||
@@ -173,12 +211,12 @@ namespace BadBuilder
|
||||
[#CCE388]██████╔╝██║ ██║██████╔╝██████╔╝╚██████╔╝██║███████╗██████╔╝███████╗██║ ██║[/]
|
||||
[#CCE388]╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═════╝ ╚═╝╚══════╝╚═════╝ ╚══════╝╚═╝ ╚═╝[/]
|
||||
|
||||
[#76B900]──────────────────────────────────────────────────────────────────────v0.21a[/]
|
||||
[#76B900]───────────────────────────────────────────────────────────────────────v0.30[/]
|
||||
───────────────────────Xbox 360 [#FF7200]BadUpdate[/] USB Builder───────────────────────
|
||||
[#848589]Created by Pdawg[/]
|
||||
[#76B900]────────────────────────────────────────────────────────────────────────────[/]
|
||||
|
||||
""");
|
||||
""");
|
||||
|
||||
static string PromptForAction() => AnsiConsole.Prompt(
|
||||
new SelectionPrompt<string>()
|
||||
|
||||
@@ -7,5 +7,10 @@
|
||||
internal const string EXTRACTED_DIR = $@"{WORKING_DIR}\Extract";
|
||||
|
||||
internal const string ContentFolder = "Content\\0000000000000000\\";
|
||||
|
||||
internal const long KB = 1024L;
|
||||
internal const long MB = 1048576L;
|
||||
internal const long GB = 1073741824L;
|
||||
internal const long TB = 1099511627776L;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user