Skip to content

Commit

Permalink
Initializes ps4k crate
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed May 5, 2024
1 parent ee9f682 commit 508a834
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 36 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ edition = "2021"

[dependencies]
bitflags = "2.5.0"
ps4k = { path = "ps4k" }
x86_64 = { version = "0.15.1", features = ["instructions"], default-features = false }

[profile.release]
opt-level = "z"

[workspace]
members = ["ps4k"]
6 changes: 6 additions & 0 deletions ps4k/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "ps4k"
version = "0.1.0"
edition = "2021"

[dependencies]
File renamed without changes.
59 changes: 59 additions & 0 deletions ps4k/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#![no_std]

use self::elf::ProgramType;

pub mod elf;

/// Struct to access internal kernel functions and variables.
pub struct Kernel {
elf: &'static [u8],
}

impl Kernel {
/// # Safety
/// `base` must point to a valid address of the kernel. Behavior is undefined if format of the
/// kernel is unknown. This should never happens unless the PS4 boot loader has been changed in
/// the future.
///
/// # Panics
/// This function may panic if format of the kernel is unknown.
pub unsafe fn new(base: *const u8) -> Self {
// Get ELF loaded size.
let e_phnum = base.add(0x38).cast::<u16>().read() as usize;
let progs = core::slice::from_raw_parts(base.add(0x40), e_phnum * 0x38);
let mut end = base as usize;

for h in progs.chunks_exact(0x38) {
// Skip non-loadable.
let ty = ProgramType::new(u32::from_le_bytes(h[0x00..0x04].try_into().unwrap()));

if !matches!(ty, ProgramType::PT_LOAD | ProgramType::PT_SCE_RELRO) {
continue;
}

// Update end address.
let addr = usize::from_le_bytes(h[0x10..0x18].try_into().unwrap());
let len = usize::from_le_bytes(h[0x28..0x30].try_into().unwrap());
let align = usize::from_le_bytes(h[0x30..0x38].try_into().unwrap());

assert!(addr >= end); // Just in case if Sony re-order the programs.

end = addr + len.next_multiple_of(align);
}

// Get loaded ELF.
let len = end - (base as usize);
let elf = unsafe { core::slice::from_raw_parts(base, len) };

Self { elf }
}

/// Returns loaded ELF of the kernel.
///
/// # Safety
/// The returned slice can contains `PF_W` programs. That mean the memory covered by this slice
/// can mutate at any time. The whole slice is guarantee to be readable.
pub unsafe fn elf(&self) -> &'static [u8] {
self.elf
}
}
43 changes: 7 additions & 36 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#![no_std]
#![no_main]

use crate::elf::ProgramType;
use crate::fs::{fsync, open, write, OpenFlags};
use crate::thread::Thread;
use core::arch::global_asm;
Expand All @@ -10,11 +9,11 @@ use core::ffi::{c_int, c_void};
use core::mem::{size_of_val, zeroed};
use core::panic::PanicInfo;
use core::ptr::null;
use ps4k::Kernel;
use x86_64::registers::control::Cr0;
use x86_64::registers::model_specific::LStar;
use x86_64::VirtAddr;

mod elf;
mod errno;
mod fs;
mod thread;
Expand Down Expand Up @@ -81,7 +80,8 @@ pub extern "C" fn main(_: *const u8) {
unsafe { patch_kernel(base) };
unsafe { Cr0::write_raw(cr0) };

// Get kernel addresses.
// Initialize ps4k crate.
let kernel = unsafe { Kernel::new(base.as_ptr()) };
unsafe { SYSENTS = (base + 0x1101760).as_ptr() };

// Create dump file.
Expand All @@ -97,52 +97,23 @@ pub extern "C" fn main(_: *const u8) {
}
};

// Get kernel size.
let e_phnum = unsafe { (base + 0x38).as_ptr::<u16>().read() as usize };
let data = unsafe { core::slice::from_raw_parts((base + 0x40).as_ptr::<u8>(), e_phnum * 0x38) };
let mut end = base.as_u64() as usize;

for h in data.chunks_exact(0x38) {
// Skip non-loadable.
let ty = ProgramType::new(u32::from_le_bytes(h[0x00..0x04].try_into().unwrap()));

if !matches!(ty, ProgramType::PT_LOAD | ProgramType::PT_SCE_RELRO) {
continue;
}

// Check if program follow the previous one.
let addr = usize::from_le_bytes(h[0x10..0x18].try_into().unwrap());

if addr < end {
notify("Some ELF programs overlapped!");
return;
}

// Update end address.
let len = usize::from_le_bytes(h[0x28..0x30].try_into().unwrap());
let align = usize::from_le_bytes(h[0x30..0x38].try_into().unwrap());

end = addr + len.next_multiple_of(align);
}

// Dump.
let len = end - (base.as_u64() as usize);
let mut data = unsafe { core::slice::from_raw_parts(base.as_ptr::<u8>(), len) };
let mut data = unsafe { kernel.elf() };

while !data.is_empty() {
// Write file.
let fd = out.as_raw_fd();
let len = min(data.len(), 0x4000);
let buf = &data[..len];
let bytes = match write(fd, buf.as_ptr(), buf.len()) {
let written = match write(fd, buf.as_ptr(), buf.len()) {
Ok(v) => v,
Err(_) => {
notify("Failed to write /mnt/usb0/kernel.elf");
return;
}
};

if bytes == 0 {
if written == 0 {
notify("Not enough space to dump the kernel");
return;
}
Expand All @@ -153,7 +124,7 @@ pub extern "C" fn main(_: *const u8) {
return;
}

data = &data[bytes..];
data = &data[written..];
}

notify("Dump completed!");
Expand Down

0 comments on commit 508a834

Please sign in to comment.