Skip to content

Commit

Permalink
revitalize readme
Browse files Browse the repository at this point in the history
  • Loading branch information
ohchase committed Mar 10, 2024
1 parent 53d5d88 commit 48f00ed
Showing 1 changed file with 98 additions and 2 deletions.
100 changes: 98 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Video game modding, reverse engineering, etc
- Can hook networking calls: recv / send
- Rendering calls: eglSwapBuffers / video game overlays

## Look at all these ~~chickens~~ targets
## Supports and tests against many targets
- ![i686-unknown-linux-gnu](https://github.com/ohchase/plt-rs/actions/workflows/i686-unknown-linux-gnu.yml/badge.svg)
- ![x86_64-unknown-linux-gnu](https://github.com/ohchase/plt-rs/actions/workflows/x86_64-unknown-linux-gnu.yml/badge.svg)
- ![aarch64-unknown-linux-gnu](https://github.com/ohchase/plt-rs/actions/workflows/aarch64-unknown-linux-gnu.yml/badge.svg)
Expand All @@ -41,7 +41,103 @@ Video game modding, reverse engineering, etc
- ![armv7-linux-androideabi](https://github.com/ohchase/plt-rs/actions/workflows/armv7-linux-androideabi.yml/badge.svg)

## Show me da code
Here we are hooking our own executables usages of libc getpid
Here we are hooking our own executables usages of libc getpid.
Refer to `examples/hook_getpid.rs` for the full example, supporting android and 32 bit.
A good chunk of the code is for the actual pointer replacement to hook the function!

```rust
/// Finding target function differs on 32 bit and 64 bit.
/// On 64 bit we want to check the addended relocations table only, opposed to the addendless relocations table.
/// Additionally, we will fall back to the plt given it is an addended relocation table.
#[cfg(target_pointer_width = "64")]
fn try_find_function<'a>(
dyn_lib: &'a DynamicLibrary,
dyn_symbols: &'a DynamicSymbols,
) -> Option<&'a plt_rs::elf64::DynRela> {
let string_table = dyn_lib.string_table();
if let Some(dyn_relas) = dyn_lib.addend_relocs() {
let dyn_relas = dyn_relas.entries().iter();
if let Some(symbol) = dyn_relas
.flat_map(|e| {
dyn_symbols
.resolve_name(e.symbol_index() as usize, string_table)
.map(|s| (e, s))
})
.filter(|(_, s)| s.eq("getpid"))
.next()
.map(|(target_function, _)| target_function)
{
return Some(symbol);
}
}

if let Some(dyn_relas) = dyn_lib.plt_rela() {
let dyn_relas = dyn_relas.entries().iter();
if let Some(symbol) = dyn_relas
.flat_map(|e| {
dyn_symbols
.resolve_name(e.symbol_index() as usize, string_table)
.map(|s| (e, s))
})
.filter(|(_, s)| s.eq("getpid"))
.next()
.map(|(target_function, _)| target_function)
{
return Some(symbol);
}
}
return None;
}

fn main() -> Result<()> {
let my_pid = unsafe { libc::getpid() };
println!("application pid is {my_pid}");

let executable_entry = find_executable().ok_or(anyhow!("unable to find target executable"))?;
println!("successfully identified executable");

let dyn_lib = DynamicLibrary::initialize(executable_entry)?;
println!("successfully initialied dynamic library for instrumentation");

let dyn_symbols = dyn_lib
.symbols()
.ok_or(anyhow!("dynamic lib should have symbols"))?;
let target_function =
try_find_function(&dyn_lib, &dyn_symbols).ok_or(anyhow!("unable to find getpid symbol"))?;
println!(
"successfully identified libc getpid offset: {:#X?}",
target_function.r_offset
);

let base_addr = dyn_lib.library().addr();
let plt_fn_ptr = (base_addr + target_function.r_offset as usize) as *mut *mut c_void;
let page_size = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) as usize };
let plt_page = ((plt_fn_ptr as usize / page_size) * page_size) as *mut c_void;
println!("page start for function is {plt_page:#X?}");

let _stored_address = unsafe {
// Set the memory page to read, write
let prot_res = libc::mprotect(plt_page, page_size, libc::PROT_WRITE | libc::PROT_READ);
if prot_res != 0 {
println!("protection res: {prot_res}");
return Err(anyhow!("mprotect to rw"));
}

// Replace the function address
let previous_address = std::ptr::replace(plt_fn_ptr, getpid as *mut _);

// Set the memory page protection back to read only
let prot_res = libc::mprotect(plt_page, page_size, libc::PROT_READ);
if prot_res != 0 {
return Err(anyhow!("mprotect to r"));
}

previous_address as *const c_void
};

let get_pid = unsafe { libc::getpid() };
println!("new pid is: {get_pid}");

Ok(())
}
```

0 comments on commit 48f00ed

Please sign in to comment.