319 lines
15 KiB
C#
319 lines
15 KiB
C#
global using DownloadItem = (string name, string url);
|
|
global using ArchiveItem = (string name, string path);
|
|
global using HomebrewApp = (string name, string folder, string entryPoint);
|
|
|
|
using System.Linq;
|
|
using Spectre.Console;
|
|
using BadBuilder.Models;
|
|
using BadBuilder.Helpers;
|
|
using BadBuilder.Utilities;
|
|
|
|
using static BadBuilder.Utilities.Constants;
|
|
|
|
namespace BadBuilder
|
|
{
|
|
internal partial class Program
|
|
{
|
|
static readonly Style OrangeStyle = new(new Color(255, 114, 0));
|
|
static readonly Style LightOrangeStyle = new(new Color(255, 172, 77));
|
|
static readonly Style PeachStyle = new(new Color(255, 216, 153));
|
|
|
|
static readonly Style GreenStyle = new(new Color(118, 185, 0));
|
|
static readonly Style GrayStyle = new(new Color(132, 133, 137));
|
|
|
|
static string XexToolPath = string.Empty;
|
|
static string TargetDriveLetter = string.Empty;
|
|
|
|
static ActionQueue actionQueue = new();
|
|
|
|
static DiskInfo targetDisk = new("Z:\\", "Fixed", 0, "", 0, int.MaxValue); // Default values just incase.
|
|
|
|
static void Main(string[] args)
|
|
{
|
|
ShowWelcomeMessage();
|
|
|
|
while (true)
|
|
{
|
|
Console.WriteLine();
|
|
string action = PromptForAction();
|
|
|
|
if (action == "Exit") Environment.Exit(0);
|
|
|
|
List<DiskInfo> disks = DiskHelper.GetDisks();
|
|
string selectedDisk = PromptDiskSelection(disks);
|
|
TargetDriveLetter = selectedDisk[..3];
|
|
|
|
int diskIndex = disks.FindIndex(disk => $"{disk.DriveLetter} ({disk.SizeFormatted}) - {disk.Type}" == selectedDisk);
|
|
targetDisk = disks[diskIndex];
|
|
|
|
bool confirmation = PromptFormatConfirmation(selectedDisk);
|
|
if (confirmation)
|
|
{
|
|
if (!FormatDisk(targetDisk)) continue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
List<ArchiveItem> downloadedFiles = DownloadRequiredFiles().Result;
|
|
ExtractFiles(downloadedFiles).Wait();
|
|
|
|
ClearConsole();
|
|
string selectedDefaultApp = "XeUnshackle";
|
|
AnsiConsole.MarkupLine("[#76B900]{0}[/] Default payload set to [bold]XeUnshackle[/].", Markup.Escape("[*]"));
|
|
|
|
AnsiConsole.MarkupLine("[#76B900]{0}[/] Copying requried files and folders.", Markup.Escape("[*]"));
|
|
foreach (var folder in Directory.GetDirectories($@"{EXTRACTED_DIR}"))
|
|
{
|
|
switch (folder.Split("\\").Last())
|
|
{
|
|
case "ABadAvatar":
|
|
string avatarPayloadPath = Path.Combine(folder, "BadUpdatePayload");
|
|
if (Directory.Exists(avatarPayloadPath))
|
|
{
|
|
EnqueueMirrorDirectory(
|
|
avatarPayloadPath,
|
|
Path.Combine(TargetDriveLetter, "BadUpdatePayload"),
|
|
5
|
|
);
|
|
}
|
|
|
|
string avatarContentPath = Path.Combine(folder, "Content");
|
|
if (Directory.Exists(avatarContentPath))
|
|
{
|
|
EnqueueMirrorDirectory(
|
|
avatarContentPath,
|
|
Path.Combine(TargetDriveLetter, "Content"),
|
|
5
|
|
);
|
|
}
|
|
break;
|
|
|
|
case "Aurora Dashboard":
|
|
string auroraDestination = Path.Combine(TargetDriveLetter, "Apps", "Aurora");
|
|
Directory.CreateDirectory(auroraDestination);
|
|
|
|
bool auroraRootHasXex = Directory.GetFiles(folder, "*.xex", SearchOption.TopDirectoryOnly).Any();
|
|
if (auroraRootHasXex)
|
|
{
|
|
EnqueueMirrorDirectory(
|
|
folder,
|
|
auroraDestination,
|
|
4
|
|
);
|
|
break;
|
|
}
|
|
|
|
string[] auroraSubDirs = Directory.GetDirectories(folder);
|
|
string[] auroraRootFiles = Directory.GetFiles(folder);
|
|
|
|
string? primaryAuroraDir = auroraSubDirs.FirstOrDefault(dir =>
|
|
Directory.GetFiles(dir, "*.xex", SearchOption.TopDirectoryOnly).Any());
|
|
|
|
if (primaryAuroraDir == null)
|
|
{
|
|
EnqueueMirrorDirectory(
|
|
folder,
|
|
auroraDestination,
|
|
4
|
|
);
|
|
break;
|
|
}
|
|
|
|
EnqueueMirrorDirectory(
|
|
primaryAuroraDir,
|
|
auroraDestination,
|
|
4
|
|
);
|
|
|
|
foreach (string subDir in auroraSubDirs.Where(dir => dir != primaryAuroraDir))
|
|
{
|
|
EnqueueMirrorDirectory(
|
|
subDir,
|
|
Path.Combine(auroraDestination, Path.GetFileName(subDir)),
|
|
4
|
|
);
|
|
}
|
|
|
|
foreach (string file in auroraRootFiles)
|
|
{
|
|
EnqueueFileCopy(
|
|
file,
|
|
Path.Combine(auroraDestination, Path.GetFileName(file)),
|
|
4
|
|
);
|
|
}
|
|
break;
|
|
|
|
case "XeXmenu":
|
|
EnqueueMirrorDirectory(
|
|
Path.Combine(folder, $"{ContentFolder}C0DE9999"),
|
|
Path.Combine(TargetDriveLetter, $"{ContentFolder}C0DE9999"),
|
|
7
|
|
);
|
|
break;
|
|
|
|
case "XeUnshackle":
|
|
string readmePath = Path.Combine(folder, "README - IMPORTANT.txt");
|
|
if (File.Exists(readmePath))
|
|
{
|
|
File.Delete(readmePath);
|
|
}
|
|
|
|
foreach (string subDirectory in Directory.GetDirectories(folder))
|
|
{
|
|
EnqueueMirrorDirectory(
|
|
subDirectory,
|
|
Path.Combine(TargetDriveLetter, Path.GetFileName(subDirectory)),
|
|
9
|
|
);
|
|
}
|
|
|
|
foreach (string file in Directory.GetFiles(folder))
|
|
{
|
|
EnqueueFileCopy(
|
|
file,
|
|
Path.Combine(TargetDriveLetter, Path.GetFileName(file)),
|
|
9
|
|
);
|
|
}
|
|
break;
|
|
|
|
case "BadUpdate":
|
|
actionQueue.EnqueueAction(async () =>
|
|
{
|
|
using (StreamWriter writer = new(Path.Combine(TargetDriveLetter, "name.txt")))
|
|
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\nConfiguration: \n- BadUpdate target binary: {selectedDefaultApp}");
|
|
|
|
Directory.CreateDirectory(Path.Combine(TargetDriveLetter, "Apps"));
|
|
await FileSystemHelper.MirrorDirectoryAsync(Path.Combine(folder, "Rock Band Blitz"), TargetDriveLetter);
|
|
}, 10);
|
|
break;
|
|
|
|
case "BadUpdate Tools":
|
|
XexToolPath = Path.Combine(folder, "XePatcher", "XexTool.exe");
|
|
break;
|
|
|
|
case "Rock Band Blitz":
|
|
EnqueueMirrorDirectory(
|
|
Path.Combine(folder, $"{ContentFolder}5841122D\\000D0000"),
|
|
Path.Combine(TargetDriveLetter, $"{ContentFolder}5841122D\\000D0000"),
|
|
8
|
|
);
|
|
break;
|
|
|
|
case "Simple 360 NAND Flasher":
|
|
actionQueue.EnqueueAction(async () =>
|
|
{
|
|
await PatchHelper.PatchXexAsync(Path.Combine(folder, "Simple 360 NAND Flasher", "Default.xex"), XexToolPath);
|
|
await FileSystemHelper.MirrorDirectoryAsync(Path.Combine(folder, "Simple 360 NAND Flasher"), Path.Combine(TargetDriveLetter, "Apps", "Simple 360 NAND Flasher"));
|
|
}, 6);
|
|
break;
|
|
|
|
default: throw new Exception($"[-] Unexpected directory in working folder: {folder}");
|
|
}
|
|
}
|
|
actionQueue.ExecuteActionsAsync().Wait();
|
|
|
|
string launchIniPath = Path.Combine(TargetDriveLetter, "launch.ini");
|
|
if (File.Exists(launchIniPath))
|
|
{
|
|
List<string> launchIniLines = File.ReadAllLines(launchIniPath).ToList();
|
|
|
|
for (int i = 0; i < launchIniLines.Count; i++)
|
|
{
|
|
if (launchIniLines[i].TrimStart().StartsWith("Default =", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
launchIniLines[i] = @"Default = Usb:\Apps\Aurora\Aurora.xex";
|
|
break;
|
|
}
|
|
}
|
|
|
|
const string commentText = "; Hallo von NiklasCFW :D";
|
|
int autoContIndex = launchIniLines.FindIndex(line =>
|
|
line.Trim().Equals("autocont = false", StringComparison.OrdinalIgnoreCase));
|
|
|
|
if (autoContIndex >= 0)
|
|
{
|
|
bool commentAlreadyPresent = autoContIndex > 0 &&
|
|
launchIniLines[autoContIndex - 1].Trim().Equals(commentText, StringComparison.OrdinalIgnoreCase);
|
|
|
|
if (!commentAlreadyPresent)
|
|
{
|
|
launchIniLines.Insert(autoContIndex, commentText);
|
|
}
|
|
}
|
|
|
|
File.WriteAllLines(launchIniPath, launchIniLines);
|
|
}
|
|
|
|
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();
|
|
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();
|
|
}
|
|
|
|
static void EnqueueMirrorDirectory(string sourcePath, string destinationPath, int priority)
|
|
{
|
|
actionQueue.EnqueueAction(async () =>
|
|
{
|
|
await FileSystemHelper.MirrorDirectoryAsync(sourcePath, destinationPath);
|
|
}, priority);
|
|
}
|
|
|
|
static void EnqueueFileCopy(string sourceFile, string destinationFile, int priority)
|
|
{
|
|
actionQueue.EnqueueAction(async () =>
|
|
{
|
|
await FileSystemHelper.CopyFileAsync(sourceFile, destinationFile);
|
|
}, 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(
|
|
"""
|
|
[#4D8C00]██████╗ █████╗ ██████╗ ██████╗ ██╗ ██╗██╗██╗ ██████╗ ███████╗██████╗[/]
|
|
[#65A800]██╔══██╗██╔══██╗██╔══██╗██╔══██╗██║ ██║██║██║ ██╔══██╗██╔════╝██╔══██╗[/]
|
|
[#76B900]██████╔╝███████║██║ ██║██████╔╝██║ ██║██║██║ ██║ ██║█████╗ ██████╔╝[/]
|
|
[#A1CF3E]██╔══██╗██╔══██║██║ ██║██╔══██╗██║ ██║██║██║ ██║ ██║██╔══╝ ██╔══██╗[/]
|
|
[#CCE388]██████╔╝██║ ██║██████╔╝██████╔╝╚██████╔╝██║███████╗██████╔╝███████╗██║ ██║[/]
|
|
[#CCE388]╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═════╝ ╚═╝╚══════╝╚═════╝ ╚══════╝╚═╝ ╚═╝[/]
|
|
|
|
[#76B900]───────────────────────────────────────────────────────────────────────v0.31[/]
|
|
───────────────────────Xbox 360 [#FF7200]BadUpdate[/] USB Builder───────────────────────
|
|
[#848589]Created by Pdawg | Forked by NiklasCFW[/]
|
|
[#76B900]────────────────────────────────────────────────────────────────────────────[/]
|
|
|
|
""");
|
|
|
|
static string PromptForAction() => AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.HighlightStyle(GreenStyle)
|
|
.AddChoices(
|
|
"Build exploit USB",
|
|
"Exit"
|
|
)
|
|
);
|
|
|
|
static void ClearConsole()
|
|
{
|
|
AnsiConsole.Clear();
|
|
ShowWelcomeMessage();
|
|
Console.WriteLine();
|
|
}
|
|
}
|
|
} |