Replaces Kernel with KernelVersion

This commit is contained in:
Putta Khunchalee 2024-05-11 20:03:02 +07:00
parent 144c1b19a7
commit 0249fd37c7
7 changed files with 88 additions and 113 deletions

View File

@ -6,12 +6,12 @@ use ps4k::offset;
mod thread;
/// Implementation of [`ps4k::version::KernelVersion`] for 11.00.
pub struct KernelVersion {
/// Implementation of [`ps4k::Kernel`] for 11.00.
pub struct Kernel {
elf: &'static [u8],
}
impl ps4k::version::KernelVersion for KernelVersion {
impl ps4k::Kernel for Kernel {
type Thread = Thread;
unsafe fn new(base: *const u8) -> Self {

View File

@ -1,11 +1,11 @@
/// Implementation of [`ps4k::version::Thread`] for 11.00.
/// Implementation of [`ps4k::thread::Thread`] for 11.00.
#[repr(C)]
pub struct Thread {
pad: [u8; 0x398],
ret: [usize; 2], // td_retval
}
impl ps4k::version::Thread for Thread {
impl ps4k::thread::Thread for Thread {
fn ret(&self, i: usize) -> usize {
self.ret[i]
}

View File

@ -1,31 +1,83 @@
#![no_std]
use self::version::KernelVersion;
use self::elf::ProgramType;
use self::thread::Thread;
use core::ffi::{c_char, c_int};
pub use ps4k_macros::*;
pub mod elf;
pub mod version;
pub mod thread;
/// Struct to access internal kernel functions and variables.
pub struct Kernel<V> {
version: V,
}
/// Provides information about the PS4 kernel for a specific version.
pub trait Kernel: Send + Sync + 'static {
type Thread: Thread;
impl<V: KernelVersion> Kernel<V> {
/// # Safety
/// `base` must point to a valid address of the kernel. Behavior is undefined if format of the
/// kernel is unknown to `V`.
/// kernel is unknown.
///
/// # Panics
/// This function may panic if format of the kernel is unknown to `V`.
pub unsafe fn new(base: *const u8) -> Self {
let version = V::new(base);
/// This function may panic if format of the kernel is unknown.
unsafe fn new(base: *const u8) -> Self;
Self { version }
}
/// Returns mapped 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.
unsafe fn elf(&self) -> &'static [u8];
pub fn version(&self) -> &V {
&self.version
/// # Safety
/// - `td` cannot be null.
/// - `path` cannot be null and must point to a null-terminated string if `kernel` is `true`.
unsafe fn kern_openat(
&self,
td: *mut Self::Thread,
fd: c_int,
path: *const c_char,
kernel: bool,
flags: c_int,
mode: c_int,
) -> c_int;
/// # Safety
/// `td` cannot be null.
unsafe fn kern_close(&self, td: *mut Self::Thread, fd: c_int) -> c_int;
/// # Safety
/// `base` must point to a valid address of the kernel. Behavior is undefined if format of the
/// kernel is unknown.
///
/// # Panics
/// This function may panic if format of the kernel is unknown.
unsafe fn get_mapped_elf(base: *const u8) -> &'static [u8] {
// 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);
core::slice::from_raw_parts(base, len)
}
}

View File

@ -1,78 +0,0 @@
pub use self::thread::*;
use crate::elf::ProgramType;
use core::ffi::{c_char, c_int};
mod thread;
/// Provides information about the PS4 kernel for a specific version.
pub trait KernelVersion: Send + Sync + 'static {
type Thread: Thread;
/// # Safety
/// `base` must point to a valid address of the kernel. Behavior is undefined if format of the
/// kernel is unknown.
///
/// # Panics
/// This function may panic if format of the kernel is unknown.
unsafe fn new(base: *const u8) -> Self;
/// Returns mapped 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.
unsafe fn elf(&self) -> &'static [u8];
/// # Safety
/// - `td` cannot be null.
/// - `path` cannot be null and must point to a null-terminated string if `kernel` is `true`.
unsafe fn kern_openat(
&self,
td: *mut Self::Thread,
fd: c_int,
path: *const c_char,
kernel: bool,
flags: c_int,
mode: c_int,
) -> c_int;
/// # Safety
/// `td` cannot be null.
unsafe fn kern_close(&self, td: *mut Self::Thread, fd: c_int) -> c_int;
/// # Safety
/// `base` must point to a valid address of the kernel. Behavior is undefined if format of the
/// kernel is unknown.
///
/// # Panics
/// This function may panic if format of the kernel is unknown.
unsafe fn get_mapped_elf(base: *const u8) -> &'static [u8] {
// 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);
core::slice::from_raw_parts(base, len)
}
}

View File

@ -7,7 +7,6 @@ use core::cmp::min;
use core::ffi::c_int;
use core::mem::{size_of_val, zeroed};
use core::panic::PanicInfo;
use ps4k::version::KernelVersion;
use ps4k::Kernel;
use x86_64::registers::model_specific::LStar;
@ -15,9 +14,6 @@ mod method;
#[cfg(method = "syscall")]
mod syscall;
#[cfg(fw = "1100")]
type Version = ps4k_1100::KernelVersion;
// The job of this custom entry point is:
//
// - Get address where our payload is loaded.
@ -72,7 +68,7 @@ pub extern "C" fn main(_: *const u8) {
// Get base address of the kernel.
let aslr = LStar::read() - 0xffffffff822001c0; // AFAIK syscall handler is same for all version.
let base = aslr + 0xffffffff82200000;
let kernel = unsafe { Kernel::<Version>::new(base.as_ptr()) };
let kernel = unsafe { init(base.as_ptr()) };
// Setup dumping method.
#[cfg(method = "syscall")]
@ -92,7 +88,7 @@ pub extern "C" fn main(_: *const u8) {
};
// Dump.
let mut data = unsafe { kernel.version().elf() };
let mut data = unsafe { kernel.elf() };
while !data.is_empty() {
// Write file.
@ -165,6 +161,11 @@ fn notify(method: &impl DumpMethod, msg: impl AsRef<[u8]>) {
.ok();
}
#[cfg(fw = "1100")]
unsafe fn init(base: *const u8) -> impl Kernel {
ps4k_1100::Kernel::new(base)
}
#[panic_handler]
fn panic(_: &PanicInfo) -> ! {
loop {}

View File

@ -2,7 +2,7 @@ use crate::method::{DumpMethod, OpenFlags, OwnedFd};
use core::ffi::{c_int, c_void, CStr};
use core::mem::transmute;
use core::num::NonZeroI32;
use ps4k::version::{KernelVersion, Thread};
use ps4k::thread::Thread;
use ps4k::Kernel;
use x86_64::registers::control::Cr0;
@ -13,14 +13,14 @@ use x86_64::registers::control::Cr0;
///
/// The reason this method exists because in order for the direct method to work we need to get the
/// first dump to find the required function addresses.
pub struct SyscallMethod<V: KernelVersion> {
sysents: &'static [Sysent<V>; 678],
pub struct SyscallMethod<K: Kernel> {
sysents: &'static [Sysent<K>; 678],
}
impl<V: KernelVersion> SyscallMethod<V> {
pub unsafe fn new(kernel: &Kernel<V>) -> Self {
impl<K: Kernel> SyscallMethod<K> {
pub unsafe fn new(kernel: &K) -> Self {
// Remove address checking from copyin, copyout and copyinstr.
let base = kernel.version().elf().as_ptr();
let base = kernel.elf().as_ptr();
let cr0 = Cr0::read_raw();
unsafe { Cr0::write_raw(cr0 & !(1 << 16)) };
@ -55,7 +55,7 @@ impl<V: KernelVersion> SyscallMethod<V> {
}
}
impl<V: KernelVersion> DumpMethod for SyscallMethod<V> {
impl<K: Kernel> DumpMethod for SyscallMethod<K> {
fn open(
&self,
path: &CStr,
@ -126,8 +126,8 @@ impl<V: KernelVersion> DumpMethod for SyscallMethod<V> {
/// Implementation of `sysent` structure.
#[repr(C)]
struct Sysent<V: KernelVersion> {
struct Sysent<K: Kernel> {
narg: c_int,
handler: unsafe extern "C" fn(td: *mut V::Thread, uap: *const c_void) -> c_int,
handler: unsafe extern "C" fn(td: *mut K::Thread, uap: *const c_void) -> c_int,
pad: [u8; 0x20],
}