mirror of
https://github.com/obhq/kernel-dumper.git
synced 2024-10-07 00:23:26 +00:00
Replaces Kernel with KernelVersion
This commit is contained in:
parent
144c1b19a7
commit
0249fd37c7
@ -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 {
|
||||
|
@ -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]
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
13
src/main.rs
13
src/main.rs
@ -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 {}
|
||||
|
@ -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],
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user