Added get/set registers to custom ptrace
This commit is contained in:
parent
cc385b7252
commit
29e463aced
|
|
@ -1,16 +1,18 @@
|
||||||
use crate::clibwrap::{ErrnoError, Pid};
|
use crate::clibwrap::{ErrnoError, Pid};
|
||||||
use bitflags::bitflags;
|
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)]
|
#[allow(non_camel_case_types)]
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
enum PTraceRequest {
|
enum PTraceRequest {
|
||||||
PTRACE_CONT = 7,
|
PTRACE_CONT = 7,
|
||||||
PTRACE_SINGLESTEP = 9,
|
PTRACE_SINGLESTEP = 9,
|
||||||
|
PTRACE_GETREGS = 12,
|
||||||
|
PTRACE_SETREGS = 13,
|
||||||
PTRACE_SYSCALL = 24,
|
PTRACE_SYSCALL = 24,
|
||||||
PTRACE_SETOPTIONS = 0x4200,
|
PTRACE_SETOPTIONS = 0x4200,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" {
|
unsafe extern "C" {
|
||||||
fn ptrace(request: PTraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> c_long;
|
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()) }
|
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 = ®isters;
|
||||||
|
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()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::clibwrap;
|
use crate::clibwrap;
|
||||||
use crate::debug_target::{CustomPTraceError, DebugError, PTraceError, RunningTarget, WaitError};
|
use crate::debug_target::{CustomPTraceError, DebugError, PTraceError, RunningTarget, WaitError};
|
||||||
use crate::syscall_info::{syscall_info, SyscallInfo, SyscallInfoError};
|
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::sys::wait::{waitid, Id, WaitPidFlag};
|
||||||
use nix::unistd::Pid;
|
use nix::unistd::Pid;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
@ -26,7 +26,7 @@ impl StoppedTarget {
|
||||||
Ok(Self { pid, breakpoints: HashMap::new() })
|
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;
|
let rip = self.get_registers()?.rip;
|
||||||
Ok(self.breakpoints.contains_key(&(rip - 1)))
|
Ok(self.breakpoints.contains_key(&(rip - 1)))
|
||||||
}
|
}
|
||||||
|
|
@ -35,7 +35,7 @@ impl StoppedTarget {
|
||||||
let mut registers = self.get_registers()?;
|
let mut registers = self.get_registers()?;
|
||||||
self.remove_breakpoint(registers.rip - 1)?;
|
self.remove_breakpoint(registers.rip - 1)?;
|
||||||
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,8 +63,8 @@ impl StoppedTarget {
|
||||||
Ok(self.to_running())
|
Ok(self.to_running())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_registers(&self) -> Result<user_regs_struct, PTraceError> {
|
pub fn get_registers(&self) -> Result<clibwrap::ptrace::registers, CustomPTraceError> {
|
||||||
Ok(nix::sys::ptrace::getregs(self.pid)?)
|
clibwrap::ptrace::get_regs(self.pid.as_raw()).map_err(CustomPTraceError)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_syscall_info(&self) -> Result<SyscallInfo, SyscallInfoError> {
|
pub fn get_syscall_info(&self) -> Result<SyscallInfo, SyscallInfoError> {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ fn single_step_all(mut target: StoppedTarget) -> color_eyre::Result<()> {
|
||||||
loop {
|
loop {
|
||||||
instruction_number += 1;
|
instruction_number += 1;
|
||||||
let regs = target.get_registers()?;
|
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()? {
|
match target.stepi()?.wait_for_something()? {
|
||||||
Either::Left(t) => target = t,
|
Either::Left(t) => target = t,
|
||||||
Either::Right(ExitedTarget { exit_code, was_pid: _was_pid }) => {
|
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!("🚧 We are on a breakpoint!")
|
||||||
}
|
}
|
||||||
println!("🔎 rip: {:#x}", t.get_registers()?.rip);
|
println!("🔎 rip: {:#x}", t.get_registers()?.rip);
|
||||||
// single_step_all(t)?;
|
single_step_all(t)?;
|
||||||
strace(t)?;
|
// strace(t)?;
|
||||||
}
|
}
|
||||||
Either::Right(ExitedTarget { exit_code, .. }) => {
|
Either::Right(ExitedTarget { exit_code, .. }) => {
|
||||||
println!("👋 Child exited with code {exit_code}");
|
println!("👋 Child exited with code {exit_code}");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue