[feat] inline hook inject
This commit is contained in:
@@ -5,6 +5,7 @@ use std::fs::File;
|
||||
use std::ops::Deref;
|
||||
use ouroboros::self_referencing;
|
||||
|
||||
|
||||
fn open_mem_map(path: &str) -> Result<Mmap, Box<dyn std::error::Error>> {
|
||||
let file = File::open(path)?;
|
||||
unsafe { Ok(Mmap::map(&file)?) }
|
||||
@@ -108,4 +109,9 @@ impl ExecuteLinkFile {
|
||||
|
||||
Ok(str.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_e_type(&self) -> u16
|
||||
{
|
||||
self.borrow_elf().header.e_type
|
||||
}
|
||||
}
|
||||
@@ -98,45 +98,11 @@ pub fn inject2(proc: &Process, seg_rw: (u64, u64)) -> Result<(), Box<dyn std::er
|
||||
|
||||
pub fn inject3(proc: &Process, seg_rw: (u64, u64)) -> Result<i32, Box<dyn std::error::Error>> // thread inject
|
||||
{
|
||||
let regs = ptrace::getregs(proc.get_pid())?;
|
||||
// Alloc rwx memory
|
||||
|
||||
let injected_inst = assemble(regs.rip as u64, |asm| {
|
||||
asm.mov(rax, 9u64)?; // Syscall 9 (mmap)
|
||||
let page_addr
|
||||
= proc.alloc_pages(1, (libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC) as u64)? as usize;
|
||||
|
||||
asm.mov(rdi, 0u64)?; // Addr
|
||||
asm.mov(rsi, 4096u64)?; // Length, we alloc a page (4K)
|
||||
asm.mov(
|
||||
rdx,
|
||||
(libc::PROT_READ | libc::PROT_WRITE | 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
|
||||
asm.int3()?; // (Important!!!) Use int3 interrupt to retrieve control flow
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
proc.write_memory_ptrace(regs.rip as usize, &injected_inst)?;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} write instructions to {:#016x}",
|
||||
regs.rip
|
||||
);
|
||||
|
||||
// Continue target
|
||||
ptrace::cont(proc.get_pid(), None)?;
|
||||
println!("{GREEN}[trace]{RESET} continue from {:#016x}", regs.rip);
|
||||
proc.wait();
|
||||
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} int3 at {:#016x}",
|
||||
ptrace::getregs(proc.get_pid())?.rip
|
||||
);
|
||||
|
||||
let regs_after_map = ptrace::getregs(proc.get_pid())?;
|
||||
let page_addr = regs_after_map.rax as usize;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} allocated page is at {:#016x}",
|
||||
page_addr
|
||||
@@ -180,8 +146,7 @@ pub fn inject3(proc: &Process, seg_rw: (u64, u64)) -> Result<i32, Box<dyn std::e
|
||||
println!("{GREEN}[trace]{RESET} write payload to {:#016x}", page_addr);
|
||||
|
||||
// Start Trigger
|
||||
// let regs = ptrace::getregs(proc.get_pid())?;
|
||||
ptrace::setregs(proc.get_pid(), regs)?;
|
||||
let regs = ptrace::getregs(proc.get_pid())?;
|
||||
|
||||
let injected_trigger = assemble(regs.rip as u64, |asm| {
|
||||
asm.mov(rax, 56u64)?; // Syscall 56 (clone)
|
||||
|
||||
@@ -6,17 +6,17 @@ use nix::unistd::Pid;
|
||||
use std::error::Error;
|
||||
use std::ffi::CString;
|
||||
use std::io::{IoSliceMut, IoSlice};
|
||||
use anyhow::Context;
|
||||
use goblin::elf64::{header, section_header};
|
||||
use nix::sys::ptrace;
|
||||
use iced_x86::code_asm::{r10, r8, r9, rax, rdi, rdx, rsi};
|
||||
|
||||
use libc::{dlsym, RTLD_NEXT};
|
||||
use libc::{dlsym, user_regs_struct, RTLD_NEXT};
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
|
||||
|
||||
use crate::helper::ExecuteLinkFile;
|
||||
use crate::helper::{assemble, ExecuteLinkFile};
|
||||
use crate::helper::map::MemoryMap;
|
||||
|
||||
const GREEN: &str = "\x1b[32m";
|
||||
const RESET: &str = "\x1b[0m";
|
||||
|
||||
fn list_processes() -> Result<HashMap<String, i32>, std::io::Error>
|
||||
{
|
||||
let mut processes = HashMap::<String, i32>::new();
|
||||
@@ -73,7 +73,7 @@ impl Process
|
||||
|
||||
let copy_len = usize::min(word_size - head_offset, data.len());
|
||||
bytes[head_offset..head_offset + copy_len].copy_from_slice(&data[..copy_len]);
|
||||
let new_word = libc::c_long::from_ne_bytes(bytes);
|
||||
let new_word = libc::c_long::from_le_bytes(bytes);
|
||||
|
||||
ptrace::write(pid, aligned_addr as *mut libc::c_void, new_word)?;
|
||||
Ok(copy_len)
|
||||
@@ -87,7 +87,7 @@ impl Process
|
||||
{
|
||||
let mut arr = [0u8; size_of::<libc::c_long>()];
|
||||
arr.copy_from_slice(data);
|
||||
let val = libc::c_long::from_ne_bytes(arr);
|
||||
let val = libc::c_long::from_le_bytes(arr);
|
||||
ptrace::write(pid, addr as *mut libc::c_void, val)?;
|
||||
Ok(size_of::<libc::c_long>())
|
||||
}
|
||||
@@ -102,7 +102,7 @@ impl Process
|
||||
let orig_word = ptrace::read(pid, addr as *mut libc::c_void)?;
|
||||
let mut bytes = orig_word.to_ne_bytes();
|
||||
bytes[..data.len()].copy_from_slice(data);
|
||||
let new_word = libc::c_long::from_ne_bytes(bytes);
|
||||
let new_word = libc::c_long::from_le_bytes(bytes);
|
||||
|
||||
ptrace::write(pid, addr as *mut libc::c_void, new_word)?;
|
||||
Ok(data.len())
|
||||
@@ -239,15 +239,30 @@ impl Process
|
||||
Ok(written)
|
||||
}
|
||||
|
||||
pub fn find_remote_proc(&self, module: &str, symbol: &str) -> Option<u64>
|
||||
pub fn find_remote_proc(
|
||||
&self,
|
||||
module: &str, // Full path of module, like '/usr/lib/libc.so.6'
|
||||
symbol: &str // Symbol name, like 'printf'
|
||||
) -> Option<u64>
|
||||
{
|
||||
let target_maps = fs::read_to_string(format!("/proc/{}/maps", self.pid)).ok()?;
|
||||
let base = MemoryMap::new(&target_maps.lines().collect::<Vec<&str>>()).module_base_address(module)?;
|
||||
|
||||
let elf = ExecuteLinkFile::prase(module).ok()?;
|
||||
let sym = elf.prase_dyn_sym(symbol).ok()?;
|
||||
|
||||
Some(sym.st_value + base)
|
||||
let target_maps = fs::read_to_string(format!("/proc/{}/maps", self.pid)).ok()?;
|
||||
let base = MemoryMap::new(&target_maps.lines().collect::<Vec<&str>>()).module_base_address(module)?;
|
||||
|
||||
let is_undefined = sym.st_shndx == section_header::SHN_UNDEF as usize;
|
||||
|
||||
if !is_undefined && sym.st_value != 0 {
|
||||
return if elf.get_e_type() == header::ET_DYN {
|
||||
Some(base + sym.st_value)
|
||||
} else {
|
||||
// ET_EXEC or others: assume st_value is absolute
|
||||
Some(sym.st_value)
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn find_got_pointer_plt(&self, symbol: &str) -> Option<u64>
|
||||
@@ -258,4 +273,63 @@ impl Process
|
||||
let r_sym = elf.get_rela_sym(symbol).ok()?;
|
||||
Some(r_sym.r_offset + self.map.module_base_address(&exe)?)
|
||||
}
|
||||
|
||||
pub fn execute_once_inplace<F>(
|
||||
&self,
|
||||
payload_builder: F
|
||||
)
|
||||
-> Result<user_regs_struct, Box<dyn Error>>
|
||||
where F: Fn(u64) -> Option<Vec<u8>>
|
||||
{
|
||||
const GREEN: &str = "\x1b[32m";
|
||||
const RESET: &str = "\x1b[0m";
|
||||
|
||||
// Save context
|
||||
let regs = ptrace::getregs(self.pid)?;
|
||||
let payload = payload_builder(regs.rip).context("payload build failed")?;
|
||||
|
||||
let buffer = self.read_memory_vm(regs.rip as usize, payload.len() + 1)?;
|
||||
let instruction = [&payload as &[u8], &[0xccu8]].concat();
|
||||
|
||||
|
||||
self.write_memory_ptrace(regs.rip as usize, &instruction)?;
|
||||
println!("{GREEN}[trace]{RESET} write instructions to {:#016x}", regs.rip);
|
||||
|
||||
// Continue target
|
||||
ptrace::cont(self.pid, None)?;
|
||||
println!("{GREEN}[trace]{RESET} continue from {:#016x}", regs.rip);
|
||||
self.wait();
|
||||
|
||||
let r = ptrace::getregs(self.pid)?;
|
||||
println!("{GREEN}[trace]{RESET} int3 at {:#016x}", r.rip);
|
||||
|
||||
self.write_memory_ptrace(regs.rip as usize, &buffer)?;
|
||||
ptrace::setregs(self.pid, regs)?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn alloc_pages(&self, count: u64, permissions: u64)
|
||||
-> Result<u64, Box<dyn Error>>
|
||||
{
|
||||
// Alloc r-x private memory
|
||||
let r = self.execute_once_inplace(|addr| {
|
||||
let r = assemble(addr, |asm| {
|
||||
asm.mov(rax, 9u64)?; // Syscall 9 (mmap)
|
||||
|
||||
asm.mov(rdi, 0u64)?; // Addr
|
||||
asm.mov(rsi, 0x1000u64 * count)?; // Length, we alloc a page (4K)
|
||||
asm.mov(rdx, permissions, )?;
|
||||
asm.mov(r10, (libc::MAP_PRIVATE | libc::MAP_ANONYMOUS) as u64)?; // Private and anonymous
|
||||
asm.mov(r8, -1i64)?; // Fd (-1 because we want anonymous)
|
||||
asm.mov(r9, 0u64)?; // Offset
|
||||
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
Ok(())
|
||||
}).ok()?;
|
||||
|
||||
Some(r)
|
||||
})?;
|
||||
|
||||
Ok(r.rax as u64)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user