From a7aed156c452685e756fa5372249a0a0e0b886d2 Mon Sep 17 00:00:00 2001 From: hammer-83 <48300721+hammer-83@users.noreply.github.com> Date: Sat, 5 Oct 2024 11:12:53 -0400 Subject: [PATCH] Framework for persisting kernel read/write primitives across JAR executions (requires new JAR loader): - Exploit independent base mechanism for kernel memory access persistance - Implement kernel r/w using ipv6 sockets - Refactored pointer classes to add some protection against kernel-space page faults - Added firmware-specific key offsets class. For now, only 1.02 is supported --- pom.xml | 2 +- .../org/ps5jb/sdk/core/AbstractPointer.java | 31 +++- .../main/java/org/ps5jb/sdk/core/Pointer.java | 5 +- ...dkSoftwareVersionUnsupportedException.java | 44 +++++ .../sdk/core/kernel/KernelAccessorIPv6.java | 47 ++++-- .../ps5jb/sdk/core/kernel/KernelOffsets.java | 50 ++++++ .../ps5jb/sdk/core/kernel/KernelPointer.java | 44 +++-- .../ps5jb/sdk/core/kernel/package-info.java | 2 +- .../java/org/ps5jb/sdk/lib/LibKernel.java | 15 ++ .../java/org/ps5jb/loader/KernelAccessor.java | 32 ++++ .../org/ps5jb/loader/KernelReadWrite.java | 154 ++++++++++++++++++ .../java/org/ps5jb/loader/RemoteLogger.java | 1 + .../main/java/org/ps5jb/client/JarMain.java | 15 +- 13 files changed, 410 insertions(+), 32 deletions(-) create mode 100644 sdk/src/main/java/org/ps5jb/sdk/core/SdkSoftwareVersionUnsupportedException.java create mode 100644 sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelOffsets.java create mode 100644 xlet/src/main/java/org/ps5jb/loader/KernelAccessor.java create mode 100644 xlet/src/main/java/org/ps5jb/loader/KernelReadWrite.java diff --git a/pom.xml b/pom.xml index 6de9a69..957a4e2 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ org.ps5jb.loader.LoaderXlet - 1.1.2 + 2.0.0 9025 diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/AbstractPointer.java b/sdk/src/main/java/org/ps5jb/sdk/core/AbstractPointer.java index a9a5c26..4f9eaba 100644 --- a/sdk/src/main/java/org/ps5jb/sdk/core/AbstractPointer.java +++ b/sdk/src/main/java/org/ps5jb/sdk/core/AbstractPointer.java @@ -2,13 +2,16 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; /** * Root parent for any class that implements a pointer to a memory. */ -public abstract class AbstractPointer { +public abstract class AbstractPointer implements Serializable { + private static final long serialVersionUID = 5085573430112354497L; + /** * Wrap the given pointer in a non-null check. Returns the same pointer if it is not NULL. * @@ -383,4 +386,30 @@ public boolean equals(Object obj) { public int hashCode() { return (new Long(this.addr)).hashCode(); } + + /** + * String representation of the pointer + * + * @return Hexadecimal address of the pointer + */ + @Override + public String toString() { + int padLength; + if (addr > 0xFFFFFFFFL) { + padLength = 16; + } else { + padLength = 8; + } + + StringBuffer buf = new StringBuffer(padLength); + buf.append("0x"); + String hexAddr = Long.toHexString(addr); + int padCount = padLength - hexAddr.length(); + for (int i = 0; i < padCount; ++i) { + buf.append("0"); + } + buf.append(hexAddr); + + return buf.toString(); + } } diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/Pointer.java b/sdk/src/main/java/org/ps5jb/sdk/core/Pointer.java index e04f986..ae6883c 100644 --- a/sdk/src/main/java/org/ps5jb/sdk/core/Pointer.java +++ b/sdk/src/main/java/org/ps5jb/sdk/core/Pointer.java @@ -11,6 +11,8 @@ * Abstraction over memory pointer operations in user-space. */ public class Pointer extends AbstractPointer { + private static final long serialVersionUID = 2230199156786175114L; + /** * Helper class to obtain an instance of Unsafe in a thread-safe manner. */ @@ -241,9 +243,6 @@ public void write(long offset, byte[] value, int valueOffset, int count) { * @throws IndexOutOfBoundsException If the read or the write beyond one of the two pointers' sizes occurs. */ public void copyTo(Pointer dest, long offset, int size) { - overflow(this, offset, size); - overflow(dest, 0, size); - byte[] data = new byte[size]; read(offset, data, 0, size); dest.write(0, data, 0, size); diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/SdkSoftwareVersionUnsupportedException.java b/sdk/src/main/java/org/ps5jb/sdk/core/SdkSoftwareVersionUnsupportedException.java new file mode 100644 index 0000000..bbd1dee --- /dev/null +++ b/sdk/src/main/java/org/ps5jb/sdk/core/SdkSoftwareVersionUnsupportedException.java @@ -0,0 +1,44 @@ +package org.ps5jb.sdk.core; + +/** + * Raised by SDK when a certain functionality requires firmware-specific knowledge, + * but it is not available. + */ +public class SdkSoftwareVersionUnsupportedException extends SdkRuntimeException { + private static final long serialVersionUID = -2958319099920522L; + + /** + * Default constructor with no message or cause. + */ + public SdkSoftwareVersionUnsupportedException() { + super(); + } + + /** + * Constructor with an error message. + * + * @param message Message corresponding to the error condition. + */ + public SdkSoftwareVersionUnsupportedException(String message) { + super(message); + } + + /** + * Constructor with a cause. + * + * @param cause Original exception that prompted this exception to be raised. + */ + public SdkSoftwareVersionUnsupportedException(Throwable cause) { + super(cause); + } + + /** + * Constructor with error message and cause. + * + * @param message Message corresponding to the error condition. + * @param cause Original exception that prompted this exception to be raised. + */ + public SdkSoftwareVersionUnsupportedException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelAccessorIPv6.java b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelAccessorIPv6.java index 7e72157..9258e15 100644 --- a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelAccessorIPv6.java +++ b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelAccessorIPv6.java @@ -1,5 +1,9 @@ package org.ps5jb.sdk.core.kernel; +import java.io.IOException; +import java.io.ObjectInputStream; + +import org.ps5jb.loader.KernelAccessor; import org.ps5jb.sdk.core.Pointer; import org.ps5jb.sdk.core.SdkException; import org.ps5jb.sdk.core.SdkRuntimeException; @@ -17,29 +21,35 @@ * Requires an existing kernel accessor on creation. */ public class KernelAccessorIPv6 implements KernelAccessor { - private final Pointer master_target_buffer; - private final Pointer slave_buffer; - private final Pointer pipemap_buffer; - private final Pointer krw_qword_store; + private static final long serialVersionUID = 8937512308105266960L; + + private Pointer master_target_buffer; + private Pointer slave_buffer; + private Pointer pipemap_buffer; + private Pointer krw_qword_store; + + private int master_sock; + private int victim_sock; - private final int master_sock; - private final int victim_sock; + private transient LibKernel libKernel; + private transient Socket socket; - private final LibKernel libKernel; - private final Socket socket; + private int[] pipe_fd; + private KernelPointer pipe_addr; - private final int[] pipe_fd; - private final KernelPointer pipe_addr; + private KernelPointer kernelBase; /** * Constructor for kernel IPv6 accessor. * * @param ofilesAddress Address of "fdt_ofiles" structure from the "proc" structure of the current process. + * @param kernelBase Address of the base of kernel text segment. * @throws SdkException If an error occurs during accessor creation. */ - public KernelAccessorIPv6(KernelPointer ofilesAddress) throws SdkException { + public KernelAccessorIPv6(KernelPointer ofilesAddress, KernelPointer kernelBase) throws SdkException { this.libKernel = new LibKernel(); this.socket = new Socket(this.libKernel); + this.kernelBase = kernelBase; final long sock_opt_size = 0x14; master_target_buffer = Pointer.calloc(sock_opt_size); @@ -93,7 +103,7 @@ public int getVictimSock() { /** * Frees resources in use by this accessor. After calling this method - * this instance should not be used. + * this instance should not be used and kernel access is no longer available. */ public synchronized void free() { if (master_target_buffer != null) { @@ -259,4 +269,17 @@ public void write8(long kernelAddress, long value) { throw new SdkRuntimeException(e); } } + + @Override + public long getKernelBase() { + return kernelBase == null ? 0 : kernelBase.addr(); + } + + private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + + // Make sure to restore libraries when de-serializing + libKernel = new LibKernel(); + socket = new Socket(this.libKernel); + } } diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelOffsets.java b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelOffsets.java new file mode 100644 index 0000000..97cd2a8 --- /dev/null +++ b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelOffsets.java @@ -0,0 +1,50 @@ +package org.ps5jb.sdk.core.kernel; + +import java.text.MessageFormat; + +import org.ps5jb.sdk.core.SdkSoftwareVersionUnsupportedException; + +/** + * Class which is able to return various interesting offsets in kernel based on the console firmware version. + * Note that currently not many firmware versions are supported + */ +public class KernelOffsets { + // Kernel text-relative offsets + public final long OFFSET_KERNEL_DATA; + + // Kernel data-relative offsets + public final long OFFSET_KERNEL_DATA_BASE_ALLPROC; + public final long OFFSET_KERNEL_DATA_BASE_SECURITYFLAGS; + public final long OFFSET_KERNEL_DATA_BASE_ROOTVNODE; + + /** + * Constructor. The firmware version can be obtained + * by making a call to sceKernelGetProsperoSystemSwVersion + * method in libkernel. Last two bytes of the result return + * the minor and the major version of the firmware. + * + * @param softwareVersion Firmware version in the form 0x[MAJOR BYTE][MINOR BYTE] + */ + public KernelOffsets(int softwareVersion) { + switch (softwareVersion) { + case 0x0102: + { + OFFSET_KERNEL_DATA = 0x01B40000; + + OFFSET_KERNEL_DATA_BASE_ALLPROC = 0x026D1BF8; + OFFSET_KERNEL_DATA_BASE_SECURITYFLAGS = 0x06241074; + OFFSET_KERNEL_DATA_BASE_ROOTVNODE = 0x06565540; + break; + } + default: + String strSwVersion = MessageFormat.format( + "{0,number,#0}.{1,number,00}", + new Object[] { + new Integer((softwareVersion >> 8) & 0xFF), + new Integer(softwareVersion & 0xFF) + } + ); + throw new SdkSoftwareVersionUnsupportedException(strSwVersion); + } + } +} diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelPointer.java b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelPointer.java index 81763a0..535c321 100644 --- a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelPointer.java +++ b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/KernelPointer.java @@ -1,5 +1,7 @@ package org.ps5jb.sdk.core.kernel; +import org.ps5jb.loader.KernelAccessor; +import org.ps5jb.loader.KernelReadWrite; import org.ps5jb.sdk.core.AbstractPointer; /** @@ -8,6 +10,11 @@ * by calling {@link KernelReadWrite#setAccessor(KernelAccessor)}. */ public class KernelPointer extends AbstractPointer { + private static final long serialVersionUID = 3445279334363239500L; + + /** Start of kernel address space. See machine/vmparam.h */ + private static final long KERNEL_ADDR_MASK = 0xFFFF800000000000L; + /** * Returns a pointer instance equivalent to the given native memory address. * @@ -18,6 +25,20 @@ public static KernelPointer valueOf(long addr) { return addr == 0 ? NULL : new KernelPointer(addr); } + /** + * Validates that the given kernel pointer has the correct kernel-space range. + * + * @param pointer Pointer to validate. + * @return Same pointer instance. + * @throws IllegalAccessError If the pointer is invalid (including NULL). + */ + public static KernelPointer validRange(KernelPointer pointer) { + if ((((pointer.addr() & KERNEL_ADDR_MASK) != KERNEL_ADDR_MASK) || pointer.addr() == -1)) { + throw new IllegalAccessError(pointer.toString()); + } + return pointer; + } + /** Static constant for NULL pointer. */ public static final KernelPointer NULL = new KernelPointer(0); @@ -31,31 +52,31 @@ public KernelPointer(long addr, Long size) { @Override public byte read1(long offset) { - overflow(this, offset, 1); + overflow(validRange(this), offset, 1); return KernelReadWrite.getAccessor().read1(this.addr + offset); } @Override public short read2(long offset) { - overflow(this, offset, 2); + overflow(validRange(this), offset, 2); return KernelReadWrite.getAccessor().read2(this.addr + offset); } @Override public int read4(long offset) { - overflow(this, offset, 4); + overflow(validRange(this), offset, 4); return KernelReadWrite.getAccessor().read4(this.addr + offset); } @Override public long read8(long offset) { - overflow(this, offset, 8); + overflow(validRange(this), offset, 8); return KernelReadWrite.getAccessor().read8(this.addr + offset); } @Override public void read(long offset, byte[] value, int valueOffset, int size) { - overflow(this, offset, size); + overflow(validRange(this), offset, size); // TODO: This can be implemented more efficiently final KernelAccessor accessor = KernelReadWrite.getAccessor(); @@ -66,31 +87,31 @@ public void read(long offset, byte[] value, int valueOffset, int size) { @Override public void write1(long offset, byte value) { - overflow(this, offset, 1); + overflow(validRange(this), offset, 1); KernelReadWrite.getAccessor().write1(this.addr + offset, value); } @Override public void write2(long offset, short value) { - overflow(this, offset, 2); + overflow(validRange(this), offset, 2); KernelReadWrite.getAccessor().write2(this.addr + offset, value); } @Override public void write4(long offset, int value) { - overflow(this, offset, 4); + overflow(validRange(this), offset, 4); KernelReadWrite.getAccessor().write4(this.addr + offset, value); } @Override public void write8(long offset, long value) { - overflow(this, offset, 8); + overflow(validRange(this), offset, 8); KernelReadWrite.getAccessor().write8(this.addr + offset, value); } @Override public void write(long offset, byte[] value, int valueOffset, int count) { - overflow(this, offset, count); + overflow(validRange(this), offset, count); // TODO: This can be implemented more efficiently final KernelAccessor accessor = KernelReadWrite.getAccessor(); @@ -108,9 +129,6 @@ public void write(long offset, byte[] value, int valueOffset, int count) { * @throws IndexOutOfBoundsException If the read or the write beyond one of the two pointers' sizes occurs. */ public void copyTo(KernelPointer dest, long offset, int size) { - overflow(this, offset, size); - overflow(dest, 0, size); - byte[] data = new byte[size]; read(offset, data, 0, size); dest.write(0, data, 0, size); diff --git a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/package-info.java b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/package-info.java index 1f220c7..98cf033 100644 --- a/sdk/src/main/java/org/ps5jb/sdk/core/kernel/package-info.java +++ b/sdk/src/main/java/org/ps5jb/sdk/core/kernel/package-info.java @@ -2,6 +2,6 @@ * This package contains various classes related to Kernel access. * Normally, any of the classes in this package are only usable if * a global kernel accessor has been installed using - * {@link org.ps5jb.sdk.core.kernel.KernelReadWrite#setAccessor(org.ps5jb.sdk.core.kernel.KernelAccessor)} + * {@link org.ps5jb.loader.KernelReadWrite#setAccessor(org.ps5jb.loader.KernelAccessor)} */ package org.ps5jb.sdk.core.kernel; diff --git a/sdk/src/main/java/org/ps5jb/sdk/lib/LibKernel.java b/sdk/src/main/java/org/ps5jb/sdk/lib/LibKernel.java index 9044087..578ebc1 100644 --- a/sdk/src/main/java/org/ps5jb/sdk/lib/LibKernel.java +++ b/sdk/src/main/java/org/ps5jb/sdk/lib/LibKernel.java @@ -446,6 +446,10 @@ public int mprotect(Pointer addr, long len, int prot) { return (int) call(mprotect, addr.addr(), len, prot); } + public int sched_yield() { + return sched_yield(0); + } + public int sched_yield(long unused) { if (sched_yield == null) { sched_yield = addrOf("sched_yield"); @@ -492,4 +496,15 @@ public byte[] sceKernelGetProsperoSystemSwVersion() { buf.free(); } } + + /** + * Helper method to return the system software version in the form 0x[MAJOR BYTE][MINOR BYTE]. + * + * @return Firmware version of the console. + * @throws org.ps5jb.sdk.core.SdkRuntimeException If an error occurred while retrieving the version. + */ + public int getSystemSoftwareVersion() { + byte[] swVer = sceKernelGetProsperoSystemSwVersion(); + return (swVer[0x1F] << 8) | swVer[0x1E]; + } } diff --git a/xlet/src/main/java/org/ps5jb/loader/KernelAccessor.java b/xlet/src/main/java/org/ps5jb/loader/KernelAccessor.java new file mode 100644 index 0000000..3503024 --- /dev/null +++ b/xlet/src/main/java/org/ps5jb/loader/KernelAccessor.java @@ -0,0 +1,32 @@ +package org.ps5jb.loader; + +import java.io.Serializable; + +/** + *

+ * Interface for accessing Kernel memory. Various exploits able to + * do so should implement this interface. + *

+ *

+ * The kernel accessor implementations should be Serializable. This is because + * Jar Loader has a different classloader than a JAR that will activate the kernel access. + * So when a JAR ends execution, Kernel Accessor state will be serialized rather than being + * stored as class instance. Upon execution of another JAR, the kernel accessor will + * be deserialized and activated again. Assuming that all JARs contain the same kernel + * accessor implementation, the kernel accessor will remain in place for subsequent JAR + * executions after it is activated initially. + *

+ */ +public interface KernelAccessor extends Serializable { + byte read1(long kernelAddress); + short read2(long kernelAddress); + int read4(long kernelAddress); + long read8(long kernelAddress); + + void write1(long kernelAddress, byte value); + void write2(long kernelAddress, short value); + void write4(long kernelAddress, int value); + void write8(long kernelAddress, long value); + + long getKernelBase(); +} diff --git a/xlet/src/main/java/org/ps5jb/loader/KernelReadWrite.java b/xlet/src/main/java/org/ps5jb/loader/KernelReadWrite.java new file mode 100644 index 0000000..f6bc153 --- /dev/null +++ b/xlet/src/main/java/org/ps5jb/loader/KernelReadWrite.java @@ -0,0 +1,154 @@ +package org.ps5jb.loader; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; + +/** + * Class managing capability of SDK to read/write the kernel memory. + */ +public final class KernelReadWrite { + private static KernelAccessor kernelAccessor; + + /** Kernel accessor state, serialized by calling {@link #saveAccessor()} */ + private static byte[] kernelAccessorState; + + /** Custom object input stream which can use a specific class loader to find the class */ + private static class ClassLoaderObjectInputStream extends ObjectInputStream { + ClassLoader classLoader; + + /** + * Constructor of the class + * + * @param in Stream from which to read the objects. + * @param classLoader Classloader to use for resolving classes. + * @throws IOException An exception occurred in the underlying stream. + */ + private ClassLoaderObjectInputStream(InputStream in, ClassLoader classLoader) throws IOException { + super(in); + this.classLoader = classLoader; + } + + @Override + protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + Class result = null; + + if (classLoader != null) { + String className = desc.getName(); + try { + result = Class.forName(className, false, classLoader); + } catch (ClassNotFoundException ex) { + Status.printStackTrace("Could not resolve the class " + className + " using classloader " + classLoader, ex); + } + } + + if (result == null) { + result = super.resolveClass(desc); + } + + return result; + } + } + + /** + * Default constructor + */ + private KernelReadWrite() { + } + + /** + * Register a global instance of a kernel accessor, responsible for + * reading and writing kernel memory. + * + * @param kernelAccessor New accessor instance. + */ + public static synchronized void setAccessor(KernelAccessor kernelAccessor) { + KernelReadWrite.kernelAccessor = kernelAccessor; + } + + /** + * Retrieve a global instance of a kernel accessor. May be null + * if none are installed. + * + * @return Instance of a kernel accessor or null. + */ + public static synchronized KernelAccessor getAccessor() { + return KernelReadWrite.kernelAccessor; + } + + /** + * Saves the current state of a global kernel accessor instance internally and + * sets it to null. + * + * @return True if state was successfully saved. + */ + public static synchronized boolean saveAccessor() { + if (kernelAccessor != null) { + try { + ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); + try { + ObjectOutputStream outStr = new ObjectOutputStream(outBytes); + try { + outStr.writeObject(kernelAccessor); + outStr.flush(); + kernelAccessorState = outBytes.toByteArray(); + } finally { + outStr.close(); + } + } finally { + outBytes.close(); + } + } catch (IOException | RuntimeException | Error e) { + Status.printStackTrace("Exception occurred while saving the kernel accessor state", e); + } + } else { + kernelAccessorState = null; + } + + // If error occurred on close, state is correctly serialized so consider it a success. + boolean result = kernelAccessorState != null || kernelAccessor == null; + if (kernelAccessorState != null) { + kernelAccessor = null; + } + + return result; + } + + /** + * Restores kernel accessor instance from a previously saved state. + * + * @param classLoader ClassLoader to use to find the kernel accessor class + * @return True if kernel accessor was activated. False if there was no previously saved + * accessor or if it could not be activated. + */ + public static synchronized boolean restoreAccessor(ClassLoader classLoader) { + if (kernelAccessorState != null) { + try { + ByteArrayInputStream inBytes = new ByteArrayInputStream(kernelAccessorState); + try { + ClassLoaderObjectInputStream inStr = new ClassLoaderObjectInputStream(inBytes, classLoader); + try { + kernelAccessor = (KernelAccessor) inStr.readObject(); + } finally { + inStr.close(); + } + } finally { + inBytes.close(); + } + } catch (ClassNotFoundException | IOException | RuntimeException | Error e) { + Status.printStackTrace("Exception occurred while restoring the kernel accessor", e); + } + } + + boolean result = kernelAccessor != null; + if (result) { + kernelAccessorState = null; + } + + return result; + } +} diff --git a/xlet/src/main/java/org/ps5jb/loader/RemoteLogger.java b/xlet/src/main/java/org/ps5jb/loader/RemoteLogger.java index 98217e6..6c60b58 100644 --- a/xlet/src/main/java/org/ps5jb/loader/RemoteLogger.java +++ b/xlet/src/main/java/org/ps5jb/loader/RemoteLogger.java @@ -113,6 +113,7 @@ public void error(String msg, Throwable e) { } finally { pw.close(); } + sb.append("\n"); sb.append(sw); } finally { try { diff --git a/xploit/src/main/java/org/ps5jb/client/JarMain.java b/xploit/src/main/java/org/ps5jb/client/JarMain.java index c387b0b..14ac290 100644 --- a/xploit/src/main/java/org/ps5jb/client/JarMain.java +++ b/xploit/src/main/java/org/ps5jb/client/JarMain.java @@ -8,6 +8,8 @@ import java.util.Enumeration; import java.util.jar.Manifest; +import org.ps5jb.loader.KernelAccessor; +import org.ps5jb.loader.KernelReadWrite; import org.ps5jb.loader.Status; /** @@ -86,14 +88,25 @@ protected void execute() throws Exception { try { Class payloadClass = Class.forName(payloadName); - Status.println("Executing payload: " + payloadName); + + // Activate Kernel accessor, if any + if (!KernelReadWrite.restoreAccessor(getClass().getClassLoader())) { + Status.println("Kernel R/W will not be available"); + } else { + Status.println("Kernel R/W restored"); + } + Runnable payload = (Runnable) payloadClass.newInstance(); payload.run(); } catch (ClassNotFoundException e) { Status.println("Unable to determine the payload to execute because the value of the attribute '" + MANIFEST_PAYLOAD_KEY + "' is not recognized: " + payloadName); } catch (ClassCastException e) { Status.println("Unable to execute the payload because it does not implement the " + Runnable.class.getName() + " interface"); + } finally { + if (KernelReadWrite.getAccessor() != null && KernelReadWrite.saveAccessor()) { + Status.println("Kernel R/W serialized for a follow-up execution"); + } } } }