Files
Collins3560 d8245f4b47 Cinebreak: one-shot PS5 BD-J jailbreak chain
Fork of Gezine's MIT-licensed BD-JB5 (BD-J sandbox escape) extended into a
full userland -> kernel -> root -> homebrew chain with automation tooling:
ps5chain.py (full-chain orchestrator), ps5find.py (LAN discovery),
probe payload, and local test harness.

All original copyright headers and licenses preserved. Credits: Gezine,
TheFlow, ufm42, john-tornblom, hammer-83, kuba-.
2026-08-09 21:11:17 +03:00

214 lines
9.2 KiB
C

/* Copyright (C) 2025 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/_iovec.h>
#include <sys/mount.h>
#include "zip.h"
#define IOVEC_SIZE(x) (sizeof(x) / sizeof(struct iovec))
#define IOVEC_ENTRY(x) {x ? x : 0, x ? strlen(x)+1 : 0}
#define JAR_PATH "/system_ex/app/NPXS40140/cdc/bdjstack.jar"
#define JAR_BAK_PATH "/system_ex/app/NPXS40140/cdc/bdjstack.jar.bak"
#define ENTRY_NAME "org/bdj/sandbox/ExploitInternal.class"
typedef struct notify_request {
char useless1[45];
char message[3075];
} notify_request_t;
int sceKernelSendNotificationRequest(int, notify_request_t*, size_t, int);
static void
notify(const char *fmt, ...) {
notify_request_t req;
va_list args;
bzero(&req, sizeof req);
va_start(args, fmt);
vsnprintf(req.message, sizeof req.message, fmt, args);
va_end(args);
sceKernelSendNotificationRequest(0, &req, sizeof req, 0);
}
static struct iovec iov_sysex[] = {
IOVEC_ENTRY("from"), IOVEC_ENTRY("/dev/ssd0.system_ex"),
IOVEC_ENTRY("fspath"), IOVEC_ENTRY("/system_ex"),
IOVEC_ENTRY("fstype"), IOVEC_ENTRY("exfatfs"),
IOVEC_ENTRY("large"), IOVEC_ENTRY("yes"),
IOVEC_ENTRY("timezone"), IOVEC_ENTRY("static"),
IOVEC_ENTRY("async"), IOVEC_ENTRY(NULL),
IOVEC_ENTRY("ignoreacl"), IOVEC_ENTRY(NULL),
};
static const unsigned char exploit_class[943] = {
0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x30, 0x00, 0x32, 0x07, 0x00,
0x19, 0x0A, 0x00, 0x01, 0x00, 0x1A, 0x0A, 0x00, 0x1B, 0x00, 0x1C, 0x07,
0x00, 0x1D, 0x0A, 0x00, 0x04, 0x00, 0x1E, 0x07, 0x00, 0x1F, 0x0A, 0x00,
0x0B, 0x00, 0x1A, 0x0A, 0x00, 0x20, 0x00, 0x21, 0x0A, 0x00, 0x20, 0x00,
0x22, 0x0A, 0x00, 0x04, 0x00, 0x23, 0x07, 0x00, 0x24, 0x07, 0x00, 0x25,
0x01, 0x00, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6C, 0x65, 0x53, 0x65,
0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x4D, 0x61, 0x6E, 0x61, 0x67, 0x65,
0x72, 0x01, 0x00, 0x03, 0x28, 0x29, 0x5A, 0x01, 0x00, 0x04, 0x43, 0x6F,
0x64, 0x65, 0x01, 0x00, 0x0F, 0x4C, 0x69, 0x6E, 0x65, 0x4E, 0x75, 0x6D,
0x62, 0x65, 0x72, 0x54, 0x61, 0x62, 0x6C, 0x65, 0x01, 0x00, 0x0A, 0x45,
0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x07, 0x00, 0x26,
0x01, 0x00, 0x06, 0x3C, 0x69, 0x6E, 0x69, 0x74, 0x3E, 0x01, 0x00, 0x03,
0x28, 0x29, 0x56, 0x01, 0x00, 0x03, 0x72, 0x75, 0x6E, 0x01, 0x00, 0x14,
0x28, 0x29, 0x4C, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67,
0x2F, 0x4F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x3B, 0x01, 0x00, 0x0A, 0x53,
0x6F, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6C, 0x65, 0x01, 0x00, 0x14,
0x45, 0x78, 0x70, 0x6C, 0x6F, 0x69, 0x74, 0x49, 0x6E, 0x74, 0x65, 0x72,
0x6E, 0x61, 0x6C, 0x2E, 0x6A, 0x61, 0x76, 0x61, 0x01, 0x00, 0x1F, 0x6F,
0x72, 0x67, 0x2F, 0x62, 0x64, 0x6A, 0x2F, 0x73, 0x61, 0x6E, 0x64, 0x62,
0x6F, 0x78, 0x2F, 0x45, 0x78, 0x70, 0x6C, 0x6F, 0x69, 0x74, 0x49, 0x6E,
0x74, 0x65, 0x72, 0x6E, 0x61, 0x6C, 0x0C, 0x00, 0x13, 0x00, 0x14, 0x07,
0x00, 0x27, 0x0C, 0x00, 0x28, 0x00, 0x29, 0x01, 0x00, 0x11, 0x6A, 0x61,
0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x42, 0x6F, 0x6F, 0x6C,
0x65, 0x61, 0x6E, 0x0C, 0x00, 0x2A, 0x00, 0x0E, 0x01, 0x00, 0x13, 0x6A,
0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x45, 0x78, 0x63,
0x65, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x07, 0x00, 0x2B, 0x0C, 0x00, 0x2C,
0x00, 0x2D, 0x0C, 0x00, 0x2E, 0x00, 0x2F, 0x0C, 0x00, 0x30, 0x00, 0x31,
0x01, 0x00, 0x10, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67,
0x2F, 0x4F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x01, 0x00, 0x27, 0x6A, 0x61,
0x76, 0x61, 0x2F, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2F,
0x50, 0x72, 0x69, 0x76, 0x69, 0x6C, 0x65, 0x67, 0x65, 0x64, 0x45, 0x78,
0x63, 0x65, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x41, 0x63, 0x74, 0x69, 0x6F,
0x6E, 0x01, 0x00, 0x27, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x73, 0x65, 0x63,
0x75, 0x72, 0x69, 0x74, 0x79, 0x2F, 0x50, 0x72, 0x69, 0x76, 0x69, 0x6C,
0x65, 0x67, 0x65, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x45, 0x78,
0x63, 0x65, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x01, 0x00, 0x1E, 0x6A, 0x61,
0x76, 0x61, 0x2F, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2F,
0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6F, 0x6E, 0x74, 0x72, 0x6F,
0x6C, 0x6C, 0x65, 0x72, 0x01, 0x00, 0x0C, 0x64, 0x6F, 0x50, 0x72, 0x69,
0x76, 0x69, 0x6C, 0x65, 0x67, 0x65, 0x64, 0x01, 0x00, 0x3D, 0x28, 0x4C,
0x6A, 0x61, 0x76, 0x61, 0x2F, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74,
0x79, 0x2F, 0x50, 0x72, 0x69, 0x76, 0x69, 0x6C, 0x65, 0x67, 0x65, 0x64,
0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x41, 0x63, 0x74,
0x69, 0x6F, 0x6E, 0x3B, 0x29, 0x4C, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C,
0x61, 0x6E, 0x67, 0x2F, 0x4F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x3B, 0x01,
0x00, 0x0C, 0x62, 0x6F, 0x6F, 0x6C, 0x65, 0x61, 0x6E, 0x56, 0x61, 0x6C,
0x75, 0x65, 0x01, 0x00, 0x10, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61,
0x6E, 0x67, 0x2F, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x01, 0x00, 0x12,
0x73, 0x65, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x4D,
0x61, 0x6E, 0x61, 0x67, 0x65, 0x72, 0x01, 0x00, 0x1E, 0x28, 0x4C, 0x6A,
0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x53, 0x65, 0x63,
0x75, 0x72, 0x69, 0x74, 0x79, 0x4D, 0x61, 0x6E, 0x61, 0x67, 0x65, 0x72,
0x3B, 0x29, 0x56, 0x01, 0x00, 0x12, 0x67, 0x65, 0x74, 0x53, 0x65, 0x63,
0x75, 0x72, 0x69, 0x74, 0x79, 0x4D, 0x61, 0x6E, 0x61, 0x67, 0x65, 0x72,
0x01, 0x00, 0x1D, 0x28, 0x29, 0x4C, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C,
0x61, 0x6E, 0x67, 0x2F, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79,
0x4D, 0x61, 0x6E, 0x61, 0x67, 0x65, 0x72, 0x3B, 0x01, 0x00, 0x07, 0x76,
0x61, 0x6C, 0x75, 0x65, 0x4F, 0x66, 0x01, 0x00, 0x16, 0x28, 0x5A, 0x29,
0x4C, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x42,
0x6F, 0x6F, 0x6C, 0x65, 0x61, 0x6E, 0x3B, 0x00, 0x21, 0x00, 0x01, 0x00,
0x0B, 0x00, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x09, 0x00,
0x0D, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x42, 0x00,
0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x16, 0xBB, 0x00, 0x01, 0x59, 0xB7,
0x00, 0x02, 0xB8, 0x00, 0x03, 0xC0, 0x00, 0x04, 0x4B, 0x2A, 0xB6, 0x00,
0x05, 0xAC, 0x4B, 0x03, 0xAC, 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x00,
0x13, 0x00, 0x06, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00,
0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x0E, 0x00, 0x0B, 0x00, 0x13, 0x00,
0x0C, 0x00, 0x14, 0x00, 0x0D, 0x00, 0x11, 0x00, 0x00, 0x00, 0x04, 0x00,
0x01, 0x00, 0x12, 0x00, 0x02, 0x00, 0x13, 0x00, 0x14, 0x00, 0x01, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
0x05, 0x2A, 0xB7, 0x00, 0x07, 0xB1, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10,
0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x01,
0x00, 0x15, 0x00, 0x16, 0x00, 0x02, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x2F,
0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x01, 0xB8, 0x00, 0x08,
0xB8, 0x00, 0x09, 0xC7, 0x00, 0x07, 0x04, 0xA7, 0x00, 0x04, 0x03, 0xB8,
0x00, 0x0A, 0xB0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00, 0x15, 0x00,
0x11, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00,
0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x18
};
static int
file_copy(const char *src, const char *dst) {
char buf[4096];
size_t n;
FILE *in = fopen(src, "rb");
if (!in) return -1;
FILE *out = fopen(dst, "wb");
if (!out) {
fclose(in);
return -1;
}
while ((n = fread(buf, 1, sizeof(buf), in)) > 0) {
fwrite(buf, 1, n, out);
}
fclose(in);
fclose(out);
return 0;
}
int
main(void) {
struct zip_t *zip = zip_open(JAR_PATH, 0, 'r');
if (!zip) {
notify("zip_open (read) failed: %s", strerror(errno));
return 1;
}
int exists = (zip_entry_open(zip, ENTRY_NAME) == 0);
if (exists) zip_entry_close(zip);
zip_close(zip);
if (exists) {
notify("bdjstack.jar already patched, skipping");
return 0;
}
// Only remount rw if we actually need to patch
if (nmount(iov_sysex, IOVEC_SIZE(iov_sysex), MNT_UPDATE)) {
notify("system_ex remount rw failed: %s", strerror(errno));
return 1;
}
if (file_copy(JAR_PATH, JAR_BAK_PATH)) {
notify("file_copy (backup) failed: %s", strerror(errno));
nmount(iov_sysex, IOVEC_SIZE(iov_sysex), MNT_UPDATE | MNT_RDONLY);
return 1;
}
zip = zip_open(JAR_PATH, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
if (!zip) {
notify("zip_open (append) failed: %s", strerror(errno));
nmount(iov_sysex, IOVEC_SIZE(iov_sysex), MNT_UPDATE | MNT_RDONLY);
return 1;
}
zip_entry_open(zip, ENTRY_NAME);
zip_entry_write(zip, exploit_class, sizeof(exploit_class));
zip_entry_close(zip);
zip_close(zip);
notify("Patched bdjstack.jar");
// Lock partition back to ro
if (nmount(iov_sysex, IOVEC_SIZE(iov_sysex), MNT_UPDATE | MNT_RDONLY)) {
notify("system_ex remount ro failed: %s", strerror(errno));
return 1;
}
return 0;
}