[feat] plt hook inject
This commit is contained in:
@@ -1,9 +1,15 @@
|
||||
use crate::elf::ExecuteLinkFile;
|
||||
use std::error::Error;
|
||||
use std::ffi::CString;
|
||||
use anyhow::Context;
|
||||
use iced_x86::code_asm::*;
|
||||
use crate::map::MemoryMap;
|
||||
use crate::processes::{get_pid_by_name, Process};
|
||||
use anyhow::Context;
|
||||
use nix::unistd::Pid;
|
||||
use std::fs;
|
||||
|
||||
use libc::user_regs_struct;
|
||||
use nix::sys::ptrace;
|
||||
|
||||
use crate::asm::assemble;
|
||||
|
||||
const GREEN: &str = "\x1b[32m";
|
||||
const RESET: &str = "\x1b[0m";
|
||||
@@ -12,8 +18,61 @@ mod disassembly;
|
||||
mod elf;
|
||||
mod map;
|
||||
mod processes;
|
||||
mod asm;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
pub fn plt_hook<F>(proc: &Process, map: &MemoryMap, symbol: &str, payload: F)
|
||||
-> Result<(), Box<dyn Error>>
|
||||
where
|
||||
F: Fn(&Process, u64, u64) -> Vec<u8>
|
||||
{
|
||||
let bias = map.module_base_address(&proc.get_exe()?).unwrap_or(0);
|
||||
let got_item_ptr = proc.find_got_pointer_plt(symbol).context("Unable to find symbol")?;
|
||||
|
||||
println!("{GREEN}[memory map]{RESET} Bias is {:#016x}", bias);
|
||||
|
||||
let got_item_byte: [u8; 8] = proc.read_memory_vm(got_item_ptr as usize, 8)?
|
||||
.try_into()
|
||||
.map_err(|_| "Failed to convert Vec to array")?;
|
||||
let got_item = u64::from_le_bytes(got_item_byte);
|
||||
println!(
|
||||
"{GREEN}[memory map]{RESET} got_item = {:#016x}", got_item
|
||||
);
|
||||
|
||||
// Alloc r-x private memory
|
||||
let regs = ptrace::getregs(proc.get_pid())?;
|
||||
let r = proc.execute_once_inplace(&assemble(regs.rip as u64, |asm| {
|
||||
asm.mov(rax, 9u64)?; // Syscall 9 (mmap)
|
||||
|
||||
asm.mov(rdi, 0u64)?; // Addr
|
||||
asm.mov(rsi, 0x1000u64)?; // Length, we alloc a page (4K)
|
||||
asm.mov(
|
||||
rdx,
|
||||
(libc::PROT_READ | libc::PROT_EXEC) as u64,
|
||||
)?; // Set protect to rwx
|
||||
asm.mov(r10, (libc::MAP_PRIVATE | libc::MAP_ANONYMOUS) as u64)?; // Private and anonymous
|
||||
asm.mov(r8, 01i64)?; // Fd (-1 because we want anonymous)
|
||||
asm.mov(r9, 0u64)?; // Offset
|
||||
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
Ok(())
|
||||
})?)?;
|
||||
|
||||
let page_addr = r.rax as u64;
|
||||
println!("{GREEN}[trace]{RESET} allocated page is at {:#016x}", page_addr);
|
||||
|
||||
let payload = payload(&proc, page_addr, got_item);
|
||||
if payload.len() > 0x1000 { return Err(Box::<dyn Error>::from("payload exceeds 0x1000 bytes")); }
|
||||
|
||||
proc.write_memory_ptrace(page_addr as usize, &payload)?;
|
||||
println!("{GREEN}[trace]{RESET} wrote {} bytes of instructions/data to {:#016x}", payload.len(), page_addr);
|
||||
proc.write_memory_ptrace(got_item_ptr as usize, &page_addr.to_le_bytes())?;
|
||||
println!("{GREEN}[trace]{RESET} rewrote got item at {:#016x} to {:#016x}, old value is {:#016x}",
|
||||
got_item_ptr, page_addr, got_item);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// Find our target program
|
||||
let pid = Pid::from_raw(get_pid_by_name("target")?);
|
||||
let process = Process::new(pid)?;
|
||||
@@ -27,23 +86,64 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
|
||||
let map = MemoryMap::new(&lines);
|
||||
let bias = map.module_base_address(&exe).unwrap_or(0);
|
||||
let write_got = process.find_got_pointer_plt("write").unwrap_or(0);
|
||||
|
||||
println!("{GREEN}[memory map]{RESET} Bias is {:#016x}", bias);
|
||||
println!("{GREEN}[memory map]{RESET} pointer to write is at {:#016x}", write_got);
|
||||
let seg_x = map.first_exec_segment(&exe).context("Can't find first exec segment")?;
|
||||
|
||||
let got_write_vec: [u8; 8] = process.read_memory_vm(write_got as usize, 8)?
|
||||
.try_into()
|
||||
.map_err(|_| "Failed to convert Vec to array")?;
|
||||
let got_write_addr = u64::from_le_bytes(got_write_vec);
|
||||
let real_write_addr =
|
||||
process.find_remote_proc("/usr/lib/libc.so.6", "write").context("Failed to find write.")?;
|
||||
ptrace::attach(pid)?;
|
||||
process.wait();
|
||||
ptrace::step(pid, None)?;
|
||||
process.wait();
|
||||
|
||||
println!(
|
||||
"{GREEN}[memory map]{RESET} real_write_addr = {:#016x}, got_write_addr = {:#016x}",
|
||||
real_write_addr, got_write_addr
|
||||
);
|
||||
// Save context
|
||||
let regs = ptrace::getregs(pid)?; // Save current registers
|
||||
|
||||
ptrace::setregs(
|
||||
pid,
|
||||
user_regs_struct {
|
||||
rip: seg_x.0,
|
||||
..regs
|
||||
},
|
||||
)?;
|
||||
|
||||
// Do inject here
|
||||
|
||||
plt_hook(&process, &map, "write", |proc, addr, old| {
|
||||
let inst = assemble(addr, |asm| {
|
||||
asm.push(rdi)?;
|
||||
asm.push(rsi)?;
|
||||
asm.push(rdx)?;
|
||||
asm.mov(rdi, 1u64)?;
|
||||
asm.mov(rsi, addr + 0x800)?;
|
||||
asm.mov(rdx, 7u64)?;
|
||||
asm.call(old)?;
|
||||
asm.pop(rdx)?;
|
||||
asm.pop(rsi)?;
|
||||
asm.pop(rdi)?;
|
||||
|
||||
asm.call(old)?;
|
||||
|
||||
asm.mov(rdi, 1u64)?;
|
||||
asm.mov(rsi, addr + 0x810)?;
|
||||
asm.mov(rdx, 2u64)?;
|
||||
asm.call(old)?;
|
||||
|
||||
asm.ret()?;
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
|
||||
let mut payload = Vec::from([0u8; 0x1000]);
|
||||
payload.splice(0..inst.len(), inst);
|
||||
payload.splice(0x800..(0x800 + 7), Vec::from("[hook] ".as_bytes()));
|
||||
payload.splice(0x810..(0x810 + 2), Vec::from("\r\n".as_bytes()));
|
||||
|
||||
return payload;
|
||||
})?;
|
||||
|
||||
// End inject logics
|
||||
|
||||
// Restore context
|
||||
ptrace::setregs(pid, regs)?;
|
||||
ptrace::detach(pid, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user