Running BadBuilder on macOS — Mac-Only Guide

This guide explains how to compile and run Pdawg-bytes/BadBuilder on macOS without Windows, a Windows VM, or a Windows PC.

The current BadBuilder release provides Windows binaries, while the source contains macOS/Linux placeholders for disk handling. The steps below add the small amount of macOS support needed to detect a USB drive and use an already-formatted FAT32 volume.

Tested approach: Apple Silicon Mac, macOS, .NET 10, 15.5 GB FAT32 USB drive.

What this guide does

The macOS build will:

  • Detect external USB drives using diskutil
  • Display the USB inside BadBuilder's Target Drive menu
  • Use an existing FAT32 USB volume
  • Download BadUpdate, XeUnshackle, Aurora, XeXMenu, Simple 360 NAND Flasher, and the required Rock Band Blitz files
  • Extract and copy the files to the USB
  • Avoid the Windows-only formatting code

It does not implement BadBuilder's Windows-specific raw-disk formatting functionality.


1. Install Apple's Command Line Tools

Open Terminal and run:

xcode-select --install

If they are already installed, verify with:

xcode-select -p

You should see:

/Library/Developer/CommandLineTools

2. Install Homebrew

If Homebrew is not already installed, install it from the official Homebrew website.

After installation, make sure Homebrew is available:

brew --version

On Apple Silicon Macs, Homebrew normally installs under:

/opt/homebrew

If Terminal tells you to add Homebrew to your PATH, follow the commands it provides.


3. Install Git and .NET

Run:

brew install git dotnet

Verify both:

git --version
dotnet --version

This guide was tested with .NET 10.


4. Download BadBuilder

Clone the repository:

git clone https://github.com/Pdawg-bytes/BadBuilder.git

Enter the repository:

cd ~/BadBuilder

Verify the files:

ls

You should see something similar to:

BadBuilder
BadBuilder.slnx
LICENSE
README.md

5. Verify the project builds

Run:

dotnet build BadBuilder/BadBuilder.csproj

The original source should build successfully, although you may see warnings related to the Windows-only disk implementation.


6. Add macOS USB-drive detection

The current source calls the Windows disk enumerator on Windows but has no implementation for macOS.

Create a new file:

cat > BadBuilder/Services/Disks/DiskService.MacOS.cs <<'EOF'
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace BadBuilder.Services.Disks;

internal static partial class DiskService
{
    private static List<DiskInfo> EnumerateDisksMacOS()
    {
        string output = RunProcess("diskutil", "list external physical");

        var disks = new List<DiskInfo>();
        var matches = Regex.Matches(output, @"^/dev/(disk\d+)\s+\(external,\s*physical\):",
            RegexOptions.Multiline);

        foreach (Match match in matches)
        {
            string device = match.Groups[1].Value;
            string info = RunProcess("diskutil", $"info /dev/{device}");

            string name = GetDiskutilValue(info, "Device / Media Name") ?? $"Disk {device}";
            string sizeText = GetDiskutilValue(info, "Disk Size") ?? "";
            string removable = GetDiskutilValue(info, "Removable Media") ?? "";
            string protocol = GetDiskutilValue(info, "Protocol") ?? "";

            long size = ParseDiskSize(sizeText);

            DriveType type =
                removable.Equals("Yes", StringComparison.OrdinalIgnoreCase) ||
                protocol.Contains("USB", StringComparison.OrdinalIgnoreCase)
                    ? DriveType.Removable
                    : DriveType.Fixed;

            disks.Add(new DiskInfo(
                device,
                name.Trim(),
                size,
                type,
                $"/dev/{device}"));
        }

        return disks;
    }

    private static string? GetDiskutilValue(string output, string key)
    {
        foreach (string line in output.Split('\n'))
        {
            if (line.TrimStart().StartsWith(key + ":", StringComparison.OrdinalIgnoreCase))
                return line[(line.IndexOf(':') + 1)..].Trim();
        }

        return null;
    }

    private static long ParseDiskSize(string value)
    {
        Match match = Regex.Match(value, @"([\d.]+)\s*(TB|GB|MB|KB|B)",
            RegexOptions.IgnoreCase);

        if (!match.Success)
            return 0;

        double number = double.Parse(match.Groups[1].Value,
            System.Globalization.CultureInfo.InvariantCulture);

        return match.Groups[2].Value.ToUpperInvariant() switch
        {
            "TB" => (long)(number * 1024 * 1024 * 1024 * 1024),
            "GB" => (long)(number * 1024 * 1024 * 1024),
            "MB" => (long)(number * 1024 * 1024),
            "KB" => (long)(number * 1024),
            _ => (long)number
        };
    }
}
EOF

7. Tell DiskService to use the macOS implementation

Open:

BadBuilder/Services/Disks/DiskService.cs

Find:

internal static List<DiskInfo> EnumerateDisks() => InvokePlatformAction(EnumerateDisksWindows, null, null);

Change it to:

internal static List<DiskInfo> EnumerateDisks() => InvokePlatformAction(EnumerateDisksWindows, EnumerateDisksMacOS, null);

Build again:

dotnet build BadBuilder/BadBuilder.csproj

A successful build confirms that macOS disk enumeration has been added.


8. Prepare the USB drive

Plug the USB drive into the Mac.

Find the physical disk:

diskutil list

Look for the external physical drive.

For example:

/dev/disk5 (external, physical)
   0: FDisk_partition_scheme
   1: DOS_FAT_32 BADUPDATE

Do not assume that /dev/disk5 will be the same on another Mac.

Always verify the disk number yourself.

Verify the FAT32 volume

If the physical disk is /dev/disk5, inspect its partition:

diskutil info /dev/disk5s1 | grep -E "Device Node|Volume Name|File System|Mount Point"

You want to see something similar to:

Device Node:        /dev/disk5s1
Volume Name:        BADUPDATE
Mount Point:        /Volumes/BADUPDATE
File System Personality: MS-DOS FAT32

If the volume is already FAT32 and mounted at:

/Volumes/BADUPDATE

you can use it without formatting it again.


9. Modify BadBuilder's macOS install behavior

Open:

BadBuilder/Application/BuilderApp.cs

Inside InstallAsync(), find the existing Windows/macOS formatting block:

if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
    Controls.WriteWarning("Drive formatting is currently only supported on Windows. Please format the drive manually to FAT32 before proceeding.");
    Controls.Pause("Press enter after you have formatted the drive.");
}
else
{
    ...
}

Replace that block with:

if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
    Config.MountPoint = "/Volumes/BADUPDATE";

    if (!Directory.Exists(Config.MountPoint))
        throw new InvalidOperationException("The BADUPDATE USB volume is not mounted at /Volumes/BADUPDATE.");

    Controls.WriteSuccess($"Using existing FAT32 drive at {Config.MountPoint}.");
}
else if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
    Controls.WriteWarning("Drive formatting is currently only supported on Windows. Please format the drive manually to FAT32 before proceeding.");
    Controls.Pause("Press enter after you have formatted the drive.");
}
else
{
    bool format = Controls.Confirm($"Are you sure you would like to format [bold]{Config.TargetDisk.Name}[/]? All data on this drive will be lost.", false, warning: true);
    Controls.PadLine();

    if (format)
    {
        Controls.WriteInfo("Formatting drive.");
        Config.MountPoint = DiskService.FormatFAT32(Config.TargetDisk);
        Controls.WriteSuccess("Drive formatted.");
    }
    else
        return;
}

This tells the macOS build:

The USB is already formatted. Use /Volumes/BADUPDATE as the installation destination.


10. Build the modified version

Run:

dotnet build BadBuilder/BadBuilder.csproj

You should get:

Build succeeded

The existing Windows-related warnings are not necessarily a problem.


11. Run BadBuilder

Because BadBuilder requests elevated privileges, run:

sudo dotnet run --project BadBuilder/BadBuilder.csproj

Enter your Mac password when prompted.


12. Select the USB

Choose:

Target drive

Your USB should appear as something similar to:

USB DISK 2.0 (15.50 GB) - Removable

Select it.

The main configuration should then show:

Drive       USB DISK 2.0
Exploit     BadUpdate
Bootstrap   XeUnshackle
Homebrew    Aurora, XeXMenu, Simple 360 NAND Flasher

13. Install

Choose:

Install

On macOS you should see:

[+] Using existing FAT32 drive at /Volumes/BADUPDATE.

BadBuilder should then:

  1. Resolve the latest releases
  2. Download the required files
  3. Extract the files
  4. Copy them to the USB
  5. Report:
[+] Your USB drive is ready for use.

14. Safely eject the USB

After BadBuilder exits, eject the physical disk.

For example, if your USB was /dev/disk5:

diskutil eject /dev/disk5

You should see:

Disk /dev/disk5 ejected

The USB can now be removed from the Mac.


Troubleshooting

BadBuilder crashes with NullReferenceException when selecting Target Drive

If you see an error involving:

DiskService.InvokePlatformAction

and:

EnumerateDisks()

the macOS disk-enumeration patch has not been applied correctly.

Verify that DiskService.cs contains:

internal static List<DiskInfo> EnumerateDisks() => InvokePlatformAction(EnumerateDisksWindows, EnumerateDisksMacOS, null);

USB isn't detected

Run:

diskutil list

Make sure the USB appears under:

external, physical

If it doesn't appear there, BadBuilder won't be able to enumerate it.


USB is detected but /Volumes/BADUPDATE doesn't exist

Check:

diskutil info /dev/diskXs1 | grep -E "Volume Name|Mount Point|File System"

Replace diskXs1 with the actual USB partition.

If the FAT32 volume isn't mounted, macOS can generally mount it with:

diskutil mount /dev/diskXs1

Then check:

ls /Volumes

You should see:

BADUPDATE

BadBuilder says the drive isn't mounted

Verify:

ls -la /Volumes/BADUPDATE

If that directory exists, BadBuilder should be able to use it.


Important Notes

Do not copy the disk number from this guide

The USB may be /dev/disk2, /dev/disk4, /dev/disk5, etc. on another Mac.

Always run:

diskutil list

and identify the correct external physical disk before performing any disk operation.

Formatting is destructive

Although this guide uses an existing FAT32 volume, formatting a USB with diskutil eraseDisk or another disk-formatting command will erase the selected disk.

Never substitute a disk number without verifying it first.

This is a macOS source-code workaround

The official BadBuilder release currently targets Windows. This guide modifies the source so that the parts needed for USB preparation work on macOS.

It does not turn every Windows-specific feature of BadBuilder into a macOS implementation.

Apple Silicon

This approach works with Apple Silicon Macs because BadBuilder is compiled locally with .NET rather than attempting to execute the Windows binary.


Quick version

Once the prerequisites are installed, the normal workflow is:

cd ~/BadBuilder

Verify the USB:

diskutil list

Verify the FAT32 volume:

diskutil info /dev/disk5s1 | grep -E "Device Node|Volume Name|File System|Mount Point"

Build:

dotnet build BadBuilder/BadBuilder.csproj

Run:

sudo dotnet run --project BadBuilder/BadBuilder.csproj

Select the USB → Install → wait for:

[+] Your USB drive is ready for use.

Then:

diskutil eject /dev/disk5

Done.

Built with LogoFlowershow