Added get/set registers to custom ptrace

This commit is contained in:
Elnath 2025-05-19 21:33:33 +02:00
parent cc385b7252
commit 29e463aced
3 changed files with 92 additions and 10 deletions

View File

@ -1,16 +1,18 @@
use crate::clibwrap::{ErrnoError, Pid};
use bitflags::bitflags;
use std::ffi::{c_long, c_void};
use std::ffi::{c_long, c_ulonglong, c_void};
use std::mem::MaybeUninit;
#[allow(non_camel_case_types)]
#[repr(u32)]
enum PTraceRequest {
PTRACE_CONT = 7,
PTRACE_SINGLESTEP = 9,
PTRACE_GETREGS = 12,
PTRACE_SETREGS = 13,
PTRACE_SYSCALL = 24,
PTRACE_SETOPTIONS = 0x4200,
}
unsafe extern "C" {
fn ptrace(request: PTraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> c_long;
}
@ -58,3 +60,83 @@ pub fn set_options(pid: Pid, options: PTraceOptions) -> Result<(), ErrnoError> {
unsafe { Err(ErrnoError::from_current_errno()) }
}
}
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(derive_more::Debug)]
pub struct registers {
#[debug("{r15:#x} ({r15})")]
pub r15: c_ulonglong,
#[debug("{r14:#x} ({r14})")]
pub r14: c_ulonglong,
#[debug("{r13:#x} ({r13})")]
pub r13: c_ulonglong,
#[debug("{r12:#x} ({r12})")]
pub r12: c_ulonglong,
#[debug("{rbp:#x} ({rbp})")]
pub rbp: c_ulonglong,
#[debug("{rbx:#x} ({rbx})")]
pub rbx: c_ulonglong,
#[debug("{r11:#x} ({r11})")]
pub r11: c_ulonglong,
#[debug("{r10:#x} ({r10})")]
pub r10: c_ulonglong,
#[debug("{r9:#x} ({r9})")]
pub r9: c_ulonglong,
#[debug("{r8:#x} ({r8})")]
pub r8: c_ulonglong,
#[debug("{rax:#x} ({rax})")]
pub rax: c_ulonglong,
#[debug("{rcx:#x} ({rcx})")]
pub rcx: c_ulonglong,
#[debug("{rdx:#x} ({rdx})")]
pub rdx: c_ulonglong,
#[debug("{rsi:#x} ({rsi})")]
pub rsi: c_ulonglong,
#[debug("{rdi:#x} ({rdi})")]
pub rdi: c_ulonglong,
#[debug(skip)]
pub orig_rax: c_ulonglong,
#[debug("{rip:#x} ({rip})")]
pub rip: c_ulonglong,
#[debug(skip)]
pub cs: c_ulonglong,
#[debug("{eflags:#x} ({eflags:#b})")]
pub eflags: c_ulonglong,
#[debug("{rsp:#x} ({rsp})")]
pub rsp: c_ulonglong,
#[debug(skip)]
pub ss: c_ulonglong,
#[debug(skip)]
pub fs_base: c_ulonglong,
#[debug(skip)]
pub gs_base: c_ulonglong,
#[debug(skip)]
pub ds: c_ulonglong,
#[debug(skip)]
pub es: c_ulonglong,
#[debug(skip)]
pub fs: c_ulonglong,
#[debug(skip)]
pub gs: c_ulonglong,
}
pub fn get_regs(pid: Pid) -> Result<registers, ErrnoError> {
let mut registers = MaybeUninit::<registers>::uninit();
let return_code = unsafe { ptrace(PTraceRequest::PTRACE_GETREGS, pid, 0 as _, registers.as_mut_ptr() as _) };
if return_code == 0 {
unsafe { Ok(registers.assume_init()) }
} else {
unsafe { Err(ErrnoError::from_current_errno()) }
}
}
pub fn set_regs(pid: Pid, registers: registers) -> Result<(), ErrnoError> {
let register_address: *const registers = &registers;
let return_code = unsafe { ptrace(PTraceRequest::PTRACE_SETREGS, pid, 0 as _, register_address as _) };
if return_code == 0 {
Ok(())
} else {
unsafe { Err(ErrnoError::from_current_errno()) }
}
}

View File

@ -1,7 +1,7 @@
use crate::clibwrap;
use crate::debug_target::{CustomPTraceError, DebugError, PTraceError, RunningTarget, WaitError};
use crate::syscall_info::{syscall_info, SyscallInfo, SyscallInfoError};
use libc::{c_long, user_regs_struct};
use libc::c_long;
use nix::sys::wait::{waitid, Id, WaitPidFlag};
use nix::unistd::Pid;
use std::collections::HashMap;
@ -26,7 +26,7 @@ impl StoppedTarget {
Ok(Self { pid, breakpoints: HashMap::new() })
}
pub fn on_breakpoint(&self) -> Result<bool, PTraceError> {
pub fn on_breakpoint(&self) -> Result<bool, CustomPTraceError> {
let rip = self.get_registers()?.rip;
Ok(self.breakpoints.contains_key(&(rip - 1)))
}
@ -35,7 +35,7 @@ impl StoppedTarget {
let mut registers = self.get_registers()?;
self.remove_breakpoint(registers.rip - 1)?;
registers.rip -= 1;
nix::sys::ptrace::setregs(self.pid, registers).map_err(PTraceError)?;
clibwrap::ptrace::set_regs(self.pid.as_raw(), registers).map_err(CustomPTraceError)?;
Ok(())
}
@ -63,8 +63,8 @@ impl StoppedTarget {
Ok(self.to_running())
}
pub fn get_registers(&self) -> Result<user_regs_struct, PTraceError> {
Ok(nix::sys::ptrace::getregs(self.pid)?)
pub fn get_registers(&self) -> Result<clibwrap::ptrace::registers, CustomPTraceError> {
clibwrap::ptrace::get_regs(self.pid.as_raw()).map_err(CustomPTraceError)
}
pub fn get_syscall_info(&self) -> Result<SyscallInfo, SyscallInfoError> {

View File

@ -14,7 +14,7 @@ fn single_step_all(mut target: StoppedTarget) -> color_eyre::Result<()> {
loop {
instruction_number += 1;
let regs = target.get_registers()?;
println!("🔎 [==> {}] rip= {:#016x}, rax = 0x{rax:x} ({rax})", instruction_number, regs.rip, rax = regs.rax);
println!("🔎 [==> {instruction_number} {regs:?}");
match target.stepi()?.wait_for_something()? {
Either::Left(t) => target = t,
Either::Right(ExitedTarget { exit_code, was_pid: _was_pid }) => {
@ -68,8 +68,8 @@ fn main() -> color_eyre::Result<()> {
println!("🚧 We are on a breakpoint!")
}
println!("🔎 rip: {:#x}", t.get_registers()?.rip);
// single_step_all(t)?;
strace(t)?;
single_step_all(t)?;
// strace(t)?;
}
Either::Right(ExitedTarget { exit_code, .. }) => {
println!("👋 Child exited with code {exit_code}");