1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
use crate::alloc::string::String;
use nnsdk::root::nn;
use std::fmt;

#[macro_export] macro_rules! install_hooks {
    (
        $(
            $hook_paths:path
        ),*
        $(,)?
    ) => {
        $(
            $crate::install_hook!(
                $hook_paths
            );
        )*
    };
}

#[repr(u8)]
pub enum Region {
    Text,
    Rodata,
    Data,
    Bss,
    Heap
}

#[repr(C)]
pub struct InlineCtx {
    pub registers: [nn::os::CpuRegister; 29],
}

impl fmt::Display for InlineCtx {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (i, reg) in self.registers.iter().enumerate() {
            unsafe { write!(f, "X[{}]: {:#08x?}\n", i, reg.x.as_ref())?; }
        }
        Ok(())
    }
}

extern "C" {
    pub fn A64HookFunction(symbol: *const libc::c_void, replace: *const libc::c_void, result: *mut *mut libc::c_void);
    pub fn A64InlineHook(symbol: *const libc::c_void, replace: *const libc::c_void);
    pub fn getRegionAddress(region: Region) -> *mut libc::c_void;
}

pub struct HookInfo {
    /// Name of the function being used as the override
    pub fn_name: &'static str,

    /// User-given name of what the hook represents
    pub name: Option<String>,

    /// Offset of where to install the hook
    pub offset: Option<u64>,

    /// Symbol of where to install the hook
    pub symbol: Option<String>,

    /// Whether or not this is an inline hook
    pub inline: bool
}

/// Type for representing a hook for this plugin
pub struct Hook {
    /// Pointer to the overloading function
    pub ptr: *const (),

    /// Info needed to identify and install this hook
    pub info: &'static HookInfo,
}

unsafe impl Sync for Hook {

}

impl Hook {
    pub fn install(&self) {
        todo!()
    }
}

#[allow(improper_ctypes)]
extern "C" {
    static __hook_array_start: Hook;
    static __hook_array_end: Hook;
}

/// Iterate over the loaded hooks for this plugin
pub fn iter_hooks() -> impl Iterator<Item = &'static Hook> {
    let hook_start = unsafe {&__hook_array_start as *const Hook};
    let hook_end = unsafe {&__hook_array_end as *const Hook};

    let hook_count = ((hook_start as usize) - (hook_end as usize)) / core::mem::size_of::<Hook>();

    crate::println!("hook_count: {}", hook_count);
    crate::println!("hook_start: {:?}", hook_start);
    crate::println!("hook_end: {:?}", hook_start);

    unsafe {
        core::slice::from_raw_parts(
            hook_start,
            hook_count
        )
    }.iter()
}