Skip to content

Commit

Permalink
Fixed some sdk mappings, added ability to reload remote logger from p…
Browse files Browse the repository at this point in the history
…ayload. Enhanced the readme. Assembly now uses Xlet version.
  • Loading branch information
hammer-83 committed Oct 1, 2024
1 parent 4553c6c commit fffc386
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 30 deletions.
25 changes: 17 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ This project uses vulnerabilities discovered in BD-J layer of PS5 firmware versi
This makes it easy to burn the BD-R disc with the loader just once and then keep on running new versions of the experimental code.
This repository provides all the necessary setup needed to create both the loader BD-R disc filesystem and the JAR to send to the PS5.

## Quickstart
1. Download the JAR Loader ISO release.
2. Burn it to a BD-R(E) disc and run it from the PS5 "Media" tab.
3. Download one of the pre-compiled JARs or compile your own by reading the steps below.
4. Send the JAR to the JAR Loader using NetCat, or using the JAR file itself, if the machine has Java installed: `java -jar [jarfile].jar [ip] [host]`.

## Prerequisites
* JDK 11 (PS5 uses Java 11 runtime)
* Apache Maven
Expand All @@ -26,24 +32,27 @@ The following properties in [pom.xml](pom.xml) can be adjusted before compiling
* `remote.logger.port` - Port on which remote logger will send the status messages.
* `remote.logger.timeout` - Number of milliseconds to wait before abandoning attempts to connect to the remote logging host. If host is down after this timeout on the first send attempt, no further tries to do remote logging will be done.

Either modify the POM directly, or pass the new values from command line, example: `mvn ... -Dloader.port=9025 -Dremote.logger.host=192.168.1.100`. To listen for messages on the remote machine when remote logger is activated, use `socat udp-recv:[remote.logger.port] stdout`.
Either modify the POM directly, or pass the new values from command line, example: `mvn clean package -Dloader.port=9025 -Dremote.logger.host=192.168.1.100`. To listen for messages on the remote machine when remote logger is activated, use `socat udp-recv:[remote.logger.port] stdout`.

Even if the remote logger is not active by default in the Xlet burned on disc, it is possible to programmatically change the remote logging server directly from the payload in the JAR file by calling [Status#resetLogger](xlet/src/main/java/org/ps5jb/loader/Status.java).

## Usage
1. Make sure environment variable `JAVA_HOME` points to the root of JDK 11. Add `${JAVA_HOME}/bin` directory to `${PATH}`.
2. Also make sure that `MAVEN_HOME` points to the root of Apache Maven installation. Add `${MAVEN_HOME}/bin` directory to `${PATH}`.
3. Create a payload to execute on PS5 by adding the implementation to the `xploit` submodule. There is no need to modify any existing files (though you are welcome if you want). Simply add your payload class in [org.ps5jb.client.payloads](xploit/src/main/java/org/ps5jb/client/payloads) package and specify its name as a parameter when compiling the project (see the next step). A few sample payloads are provided in this package already.
4. Execute `mvn clean package -Dxploit.payload=[payload classname]` from the root of the project. It should produce the following artifacts:
* Directory `assembly/target/assembly-[version]` contains all the files that should be burned to the BD-R.
* File `xploit/target/xploit-[version].jar` contains the code that can be sent repeatedly to the PS5 once the loader is deployed.
To avoid having to specify the payload every time with a `-D` switch (in step 8 as well), you can also change the property `xploit.payload` in [pom.xml](xploit/pom.xml) of the [xploit](xploit) project.
5. Burn the BD-R (better yet BD-RE), then insert it into the PS5 and launch "PS5 JAR Loader" from Media / Disc Player.
6. A message on screen should inform about loader waiting for JAR.
7. Send the JAR using the command:
a. Directory `assembly/target/assembly-[version]` contains all the files that should be burned to a BD-R disc.
b. File `xploit/target/xploit-[version].jar` contains the code that can be sent repeatedly to the PS5 once the loader is deployed.
To avoid having to specify the payload every time with a `-D` switch (in step 9 as well), you can also change the property `xploit.payload` in [pom.xml](xploit/pom.xml) of the [xploit](xploit) project.
5. Burn the BD-R (better yet BD-RE) with the contents from the directory mentioned in the step 4a. Note that re-burning the JAR loader disc is only necessary when the source of [xlet](xlet) or [assembly](assembly) modules is changed.
6. Insert the disc into the PS5 and launch "PS5 JAR Loader" from Media / Disc Player.
7. A message on screen should inform about loader waiting for JAR.
8. Send the JAR using the command:
```shell
java -jar xploit/target/xploit-[version].jar <ps5 ip address>`
```
PS5 should inform on screen about the status of the upload and the execution.
8. Once execution is complete, the loader will wait for a new JAR. Do the necessary modifications in `xploit` project, recompile using `mvn package` and re-execute #7 to retry as many times as necessary.
9. Once execution is complete, the loader will wait for a new JAR. Do the necessary modifications in `xploit` project, recompile using `mvn package` and re-execute step 8 to retry as many times as necessary.

## Notes
1. To use with IntelliJ, point `File -> Open` dialog to the root of the project. Maven import will occur. Then follow manual steps in [IntelliJ Project Structure](#intellij-project-structure) to adjust the dependencies so that IntelliJ sees BD-J classes ahead of JDK classes.
Expand Down
9 changes: 5 additions & 4 deletions assembly/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

<groupId>org.ps5jb</groupId>
<artifactId>assembly</artifactId>
<version>${xlet.version}</version>
<packaging>pom</packaging>
<description>Builds the filesystem that can be burned onto a BD-R disc to be run on PS5.</description>

Expand Down Expand Up @@ -139,25 +140,25 @@
<dependency>
<groupId>net.java.bd.tools</groupId>
<artifactId>bdjo</artifactId>
<version>${project.version}</version>
<version>${project.parent.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.java.bd.tools</groupId>
<artifactId>movieobject</artifactId>
<version>${project.version}</version>
<version>${project.parent.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.java.bd.tools</groupId>
<artifactId>index</artifactId>
<version>${project.version}</version>
<version>${project.parent.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.java.bd.tools</groupId>
<artifactId>id</artifactId>
<version>${project.version}</version>
<version>${project.parent.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/main/java/org/ps5jb/sdk/include/sys/ErrNo.java
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ public SdkException getLastException(Class clazz, String keySuffix, Object ... f
} else if (lastError == ErrNo.ENOMEM) {
result = new OutOfMemoryException(errorMessage);
} else {
result = new SdkException(ErrorMessages.getClassErrorMessage(clazz, errorMessageKey, lastError));
result = new SdkException(ErrorMessages.getClassErrorMessage(clazz, keySuffix, lastError));
}

return result;
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/main/java/org/ps5jb/sdk/include/sys/MMan.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public void memoryUnmap(Pointer addr, long len) throws InvalidValueException {
public void memoryProtect(Pointer addr, long len, ProtectionFlag ... prot) throws InvalidValueException, OperationNotPermittedException {
long ret = this.libKernel.mprotect(addr, len, ProtectionFlag.or(prot));
if (ret == -1) {
SdkException ex = errNo.getLastException(getClass(), "memoryUnmap");
SdkException ex = errNo.getLastException(getClass(), "memoryProtect");
if (ex instanceof InvalidValueException) {
throw (InvalidValueException) ex;
} else if (ex instanceof OperationNotPermittedException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,19 @@
*/
public final class RtPrioType implements Comparable {
/** Real time process. */
public static final RtPrioType RTP_PRIO_REALTIME = new RtPrioType((short) 1, "RTP_PRIO_REALTIME");
public static final RtPrioType RTP_PRIO_REALTIME = new RtPrioType((short) 2, "RTP_PRIO_REALTIME");
/** Time sharing process. */
public static final RtPrioType RTP_PRIO_NORMAL = new RtPrioType((short) 2, "RTP_PRIO_NORMAL");
public static final RtPrioType RTP_PRIO_NORMAL = new RtPrioType((short) 3, "RTP_PRIO_NORMAL");
/** Idle process. */
public static final RtPrioType RTP_PRIO_IDLE = new RtPrioType((short) 3, "RTP_PRIO_IDLE");
public static final RtPrioType RTP_PRIO_IDLE = new RtPrioType((short) 4, "RTP_PRIO_IDLE");

public static final RtPrioType RTP_PRIO_FIFO_BIT = new RtPrioType((short) 4, "RTP_PRIO_FIFO_BIT");
public static final RtPrioType RTP_PRIO_FIFO = new RtPrioType((short) 5, "RTP_PRIO_FIFO");
public static final RtPrioType RTP_PRIO_FIFO = new RtPrioType((short) (8 | RTP_PRIO_REALTIME.value), "RTP_PRIO_FIFO");

/** All possible RtPrioType values. */
private static final RtPrioType[] values = new RtPrioType[] {
RTP_PRIO_REALTIME,
RTP_PRIO_NORMAL,
RTP_PRIO_IDLE,
RTP_PRIO_FIFO_BIT,
RTP_PRIO_FIFO
};

Expand Down
45 changes: 40 additions & 5 deletions sdk/src/main/java/org/ps5jb/sdk/lib/LibKernel.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.ps5jb.sdk.core.Library;
import org.ps5jb.sdk.core.Pointer;
import org.ps5jb.sdk.core.SdkRuntimeException;
import org.ps5jb.sdk.include.sys.ErrNo;
import org.ps5jb.sdk.res.ErrorMessages;

/**
* <p>
Expand Down Expand Up @@ -51,6 +53,7 @@ public class LibKernel extends Library {
private Pointer mprotect;
private Pointer sched_yield;
private Pointer sceKernelGetCurrentCpu;
private Pointer sceKernelGetProsperoSystemSwVersion;

/**
* Constructor.
Expand All @@ -60,7 +63,7 @@ public LibKernel() {
}

public int sceKernelSendNotificationRequest(String msg) {
long size = 0xC30;
final long size = 0xC30;
Pointer buf = Pointer.calloc(size);
try {
buf.write4(0x10, -1);
Expand Down Expand Up @@ -341,23 +344,23 @@ public int shm_unlink(Pointer path) {
shm_unlink = addrOf("shm_unlink");
}

return (int) call(shm_unlink);
return (int) call(shm_unlink, path.addr());
}

public Pointer mmap(Pointer addr, long len, int prot, int flags, int fd, long offset) {
if (mmap == null) {
mmap = addrOf("mmap");
}

return Pointer.valueOf(call(mmap, addr.addr(), len, prot, flags, fd, offset));
return new Pointer(call(mmap, addr.addr(), len, prot, flags, fd, offset), new Long(len));
}

public int munmap(Pointer addr, long len) {
if (munmap == null) {
munmap = addrOf("munmap");
}

return (int) call(munmap);
return (int) call(munmap, addr.addr(), len);
}

public int ftruncate(int fd, long length) {
Expand Down Expand Up @@ -397,7 +400,7 @@ public int write(int fd, Pointer buf, long nbytes) {
write = addrOf("write");
}

return (int) call(write);
return (int) call(write, fd, buf.addr(), nbytes);
}

public int _umtx_op(Pointer obj, int op, long val, Pointer uaddr, Pointer uaddr2) {
Expand Down Expand Up @@ -430,4 +433,36 @@ public int sceKernelGetCurrentCpu() {
}
return (int) call(sceKernelGetCurrentCpu);
}

/**
* Retrieve the PS5 system software version information.
*
* @return Buffer with the version information.
* @throws org.ps5jb.sdk.core.SdkRuntimeException If an error occurred while retrieving the version.
*/
public byte[] sceKernelGetProsperoSystemSwVersion() {
final long size = 0x28;
Pointer buf = Pointer.calloc(size);
try {
buf.write8(size);

if (sceKernelGetProsperoSystemSwVersion == null) {
sceKernelGetProsperoSystemSwVersion = addrOf("sceKernelGetProsperoSystemSwVersion");
}

int ret = (int) call(sceKernelGetProsperoSystemSwVersion, buf.addr());

if (ret != 0) {
throw new SdkRuntimeException(ErrorMessages.getClassErrorMessage(LibKernel.class, "sceKernelGetProsperoSystemSwVersion", "0x" + Integer.toHexString(ret)));
}

final long resultOffset = 0x8L;
final int resultSize = (int) (size - resultOffset);
byte[] result = new byte[resultSize];
buf.read(resultOffset, result, 0, resultSize);
return result;
} finally {
buf.free();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,23 @@ core.CallContext.maxCallArguments=Maximum of {0} arguments expected. Received: {
core.CallContext.nestedCall=Nested call context execution is not supported
core.Library.symbolNotFound=Symbol ''{0}'' not found in library {1}

include.sys.CpuSet.setAffinity=Unexpected error occurred while attempting to set CPU affinity. Error code: %d.
lib.LibKernel.sceKernelGetProsperoSystemSwVersion=Call to retrieve the PS5 system version returned an error code: {0}.

include.sys.CpuSet.setAffinity=Unexpected error occurred while attempting to set CPU affinity. Error code: {0}.
include.sys.CpuSet.setAffinity.EINVAL=The level, which or mask argument was not a valid value.
include.sys.CpuSet.setAffinity.EDEADLK=The call would leave a thread without a valid CPU to run on because the set does not overlap with the thread's anonymous mask.
include.sys.CpuSet.setAffinity.EFAULT=The mask pointer passed was invalid.
include.sys.CpuSet.setAffinity.ESRCH=The object specified by the id and which arguments could not be found.
include.sys.CpuSet.setAffinity.ERANGE=The cpusetsize was either preposterously large or smaller than the kernel set size.
include.sys.CpuSet.setAffinity.EPERM=The calling process did not have the credentials required to complete the operation.
include.sys.cpuset.CpuLevelType.invalidValue=Not a valid CpuLevel value: {0}
include.sys.cpuset.CpuWhichType.invalidValue=Not a valid CpuWhich value: {0}
include.sys.cpuset.CpuLevelType.invalidValue=Not a valid CpuLevelType value: {0}
include.sys.cpuset.CpuWhichType.invalidValue=Not a valid CpuWhichType value: {0}
include.sys.dirent.DirType.invalidValue=Not a valid DirType value: {0}
include.sys.fcntl.OpenFlag.invalidValue=Not a valid OpenFlag value: {0}
include.sys.FCntl.open.EACCES=Access denied.
include.sys.rtprio.RtPrioType.invalidValue=Not a valid RtPrioType value: {0}
include.UniStd.setAffinity.EPERM=The user is not the super user and the ID specified is not the real, effective ID, or saved ID.
23 changes: 21 additions & 2 deletions xlet/src/main/java/org/ps5jb/loader/Status.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,27 @@ private static void initLogger() {
* Cleanup method which should be called just before the app termination to release the resources.
*/
public static void close() {
if (LOGGER != null) {
LOGGER.close();
synchronized (Status.class) {
if (LOGGER != null) {
LOGGER.close();
}
}
}

/**
* Change the address of the server receiving remote logging output.
*
* @param host IP address or the hostname of the remote logging server. If null, remote logger will be deactivated.
* @param port Port on which the server listens for logging message.
* @param timeout Connect timeout to the remote logging server.
*/
public static void resetLogger(String host, int port, int timeout) {
synchronized (Status.class) {
close();

if (System.getSecurityManager() == null && host != null) {
LOGGER = new RemoteLogger(host, port, timeout);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import java.util.Iterator;
import java.util.Properties;
import java.util.TreeSet;
import java.util.logging.Logger;

import org.ps5jb.loader.Config;
import org.ps5jb.loader.Status;

/**
Expand All @@ -16,6 +18,14 @@ public class PrintSystemProperties implements Runnable {
*/
@Override
public void run() {
// Sample: disable remote logger
Status.resetLogger(null, 0, 0);
Status.println("The following message will not show up on the remote logging server");

// Sample: enable default remote logger
Status.resetLogger(Config.getLoggerHost(), Config.getLoggerPort(), Config.getLoggerTimeout());
Status.println("The following message will show up on the remote logging server");

Properties props = System.getProperties();

Enumeration propNames = props.propertyNames();
Expand Down

0 comments on commit fffc386

Please sign in to comment.