Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add API to read & write registers for Linux #98

Merged
merged 4 commits into from
Nov 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ security-framework-sys = "1.0"

# Dependencies specific to Linux
[target.'cfg(target_os="linux")'.dependencies]
procfs = "0.8.0"
procfs = "0.9.0"

[target.'cfg(target_os="windows")'.dependencies]
winapi = { version = "0.3.9", features = ["winuser","processthreadsapi","winbase","minwinbase","debugapi","winnt","memoryapi","dbghelp"] }
Expand Down
23 changes: 14 additions & 9 deletions examples/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ mod example {
glutin::window::WindowBuilder, Display, Surface,
};
use headcrab::{
symbol::DisassemblySource, symbol::RelocatedDwarf, target::LinuxTarget, target::UnixTarget,
CrabResult,
symbol::DisassemblySource, symbol::RelocatedDwarf, target::LinuxTarget, target::Registers,
target::UnixTarget, CrabResult,
};
use imgui::{im_str, ClipboardBackend, Condition, FontSource, ImStr, ImString};
use imgui_glium_renderer::Renderer;
Expand Down Expand Up @@ -210,7 +210,7 @@ mod example {
.size([395.0, 390.0], Condition::FirstUseEver)
.build(ui, || {
if let Err(err) = (|| -> CrabResult<()> {
let ip = remote.read_regs()?.rip;
let ip = remote.read_regs()?.ip();
let mut code = [0; 64];
unsafe {
remote.read().read(&mut code, ip as usize).apply()?;
Expand Down Expand Up @@ -241,7 +241,12 @@ mod example {

context.load_debuginfo_if_necessary()?;

let regs = context.remote.as_ref().unwrap().read_regs()?;
let regs = context
.remote
.as_ref()
.unwrap()
.main_thread()?
.read_regs()?;

let mut stack: [usize; 1024] = [0; 1024];
unsafe {
Expand All @@ -250,7 +255,7 @@ mod example {
.as_ref()
.unwrap()
.read()
.read(&mut stack, regs.rsp as usize)
.read(&mut stack, regs.sp() as usize)
.apply()?;
}

Expand All @@ -259,16 +264,16 @@ mod example {
headcrab::symbol::unwind::frame_pointer_unwinder(
context.debuginfo(),
&stack[..],
regs.rip as usize,
regs.rsp as usize,
regs.rbp as usize,
regs.ip() as usize,
regs.sp() as usize,
regs.bp().unwrap() as usize, // TODO: `unwrap` is unsafe for non-x86 platforms
)
.collect()
}
BacktraceType::Naive => headcrab::symbol::unwind::naive_unwinder(
context.debuginfo(),
&stack[..],
regs.rip as usize,
regs.ip() as usize,
)
.collect(),
};
Expand Down
109 changes: 42 additions & 67 deletions examples/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod example {

use headcrab::{
symbol::{DisassemblySource, RelocatedDwarf, Snippet},
target::{AttachOptions, LinuxTarget, UnixTarget},
target::{AttachOptions, LinuxTarget, Registers, UnixTarget},
CrabResult,
};

Expand Down Expand Up @@ -359,7 +359,7 @@ mod example {
return show_backtrace(context, &sub_cmd);
}
ReplCommand::Disassemble(()) => {
let ip = context.remote()?.read_regs()?.rip;
let ip = context.remote()?.read_regs()?.ip();
let mut code = [0; 64];
unsafe {
context
Expand Down Expand Up @@ -475,8 +475,8 @@ mod example {
}

fn show_locals(context: &mut Context) -> CrabResult<()> {
let regs = context.remote()?.read_regs()?;
let func = regs.rip as usize;
let regs = context.remote()?.main_thread()?.read_regs()?;
let func = regs.ip() as usize;
let res = context.debuginfo().with_addr_frames(
func,
|func, mut frames: headcrab::symbol::FrameIter| {
Expand Down Expand Up @@ -512,9 +512,9 @@ mod example {
.function_debuginfo()
.ok_or_else(|| "No dwarf debuginfo for function".to_owned())?;

let mut eval_ctx = X86_64EvalContext {
let mut eval_ctx = EvalContext {
frame_base: None,
regs,
regs: Box::new(regs),
};

// FIXME handle DW_TAG_inlined_subroutine with DW_AT_frame_base in parent DW_TAG_subprogram
Expand All @@ -531,7 +531,7 @@ mod example {
match res[0].location {
gimli::Location::Register {
register: gimli::X86_64::RBP,
} => eval_ctx.frame_base = Some(regs.rbp),
} => eval_ctx.frame_base = regs.bp(),
ref loc => unimplemented!("{:?}", loc), // FIXME
}
}
Expand Down Expand Up @@ -564,30 +564,30 @@ mod example {
fn get_call_stack(context: &mut Context, bt_type: &BacktraceType) -> CrabResult<Vec<usize>> {
context.load_debuginfo_if_necessary()?;

let regs = context.remote()?.read_regs()?;
let regs = context.remote()?.main_thread()?.read_regs()?;

let mut stack: [usize; 1024] = [0; 1024];
unsafe {
context
.remote()?
.read()
.read(&mut stack, regs.rsp as usize)
.read(&mut stack, regs.sp() as usize)
.apply()?;
}

let call_stack: Vec<_> = match *bt_type {
BacktraceType::FramePtr => headcrab::symbol::unwind::frame_pointer_unwinder(
context.debuginfo(),
&stack[..],
regs.rip as usize,
regs.rsp as usize,
regs.rbp as usize,
regs.ip() as usize,
regs.sp() as usize,
regs.bp().unwrap() as usize, // TODO: fix `unwrap` for non-x86 platforms
)
.collect(),
BacktraceType::Naive => headcrab::symbol::unwind::naive_unwinder(
context.debuginfo(),
&stack[..],
regs.rip as usize,
regs.ip() as usize,
)
.collect(),
};
Expand Down Expand Up @@ -658,48 +658,23 @@ mod example {
Ok(())
}

fn get_linux_x86_64_reg(
regs: libc::user_regs_struct,
) -> impl Fn(gimli::Register, gimli::ValueType) -> gimli::Value {
move |reg, ty| {
let val = match reg {
gimli::X86_64::RAX => regs.rax,
gimli::X86_64::RBX => regs.rbx,
gimli::X86_64::RCX => regs.rcx,
gimli::X86_64::RDX => regs.rdx,
gimli::X86_64::RSI => regs.rsi,
gimli::X86_64::RDI => regs.rdi,
gimli::X86_64::RSP => regs.rsp,
gimli::X86_64::RBP => regs.rbp,
gimli::X86_64::R9 => regs.r9,
gimli::X86_64::R10 => regs.r10,
gimli::X86_64::R11 => regs.r11,
gimli::X86_64::R12 => regs.r12,
gimli::X86_64::R13 => regs.r13,
gimli::X86_64::R14 => regs.r14,
gimli::X86_64::R15 => regs.r15,
reg => unimplemented!("{:?}", reg), // FIXME
};
match ty {
gimli::ValueType::Generic => gimli::Value::Generic(val),
gimli::ValueType::U64 => gimli::Value::U64(val),
_ => unimplemented!(),
}
}
}

struct X86_64EvalContext {
struct EvalContext {
frame_base: Option<u64>,
regs: libc::user_regs_struct,
regs: Box<dyn headcrab::target::Registers>,
}

impl headcrab::symbol::dwarf_utils::EvalContext for X86_64EvalContext {
impl headcrab::symbol::dwarf_utils::EvalContext for EvalContext {
fn frame_base(&self) -> u64 {
self.frame_base.unwrap()
}

fn register(&self, register: gimli::Register, base_type: gimli::ValueType) -> gimli::Value {
get_linux_x86_64_reg(self.regs)(register, base_type)
let val = self.regs.reg_for_dwarf(register).unwrap();
match base_type {
gimli::ValueType::Generic => gimli::Value::Generic(val),
gimli::ValueType::U64 => gimli::Value::U64(val),
_ => unimplemented!(),
}
}

fn memory(
Expand All @@ -715,7 +690,7 @@ mod example {

fn show_local<'ctx>(
kind: &str,
eval_ctx: &X86_64EvalContext,
eval_ctx: &EvalContext,
local: headcrab::symbol::Local<'_, 'ctx>,
) -> CrabResult<()> {
let value = match local.value() {
Expand Down Expand Up @@ -778,20 +753,20 @@ mod example {
run_function, stack
);

let orig_regs = inj_ctx.target().read_regs()?;
let regs = libc::user_regs_struct {
rip: run_function,
rsp: stack,
..orig_regs
};
inj_ctx.target().write_regs(regs)?;
// TODO: replace `main_thread` with the current thread when we'll have it.
let orig_regs = inj_ctx.target().main_thread()?.read_regs()?;
let mut regs = orig_regs.clone();
regs.set_ip(run_function);
regs.set_sp(stack);
inj_ctx.target().main_thread()?.write_regs(regs)?;

let status = inj_ctx.target().unpause()?;
println!(
"{:?} at 0x{:016x}",
status,
inj_ctx.target().read_regs()?.rip
inj_ctx.target().read_regs()?.ip()
);
inj_ctx.target().write_regs(orig_regs)?;
inj_ctx.target().main_thread()?.write_regs(orig_regs)?;

Ok(())
}
Expand Down Expand Up @@ -841,21 +816,21 @@ mod example {
run_function, stack
);

let orig_regs = inj_ctx.target().read_regs()?;
println!("orig rip: {:016x}", orig_regs.rip);
let regs = libc::user_regs_struct {
rip: run_function,
rsp: stack,
..orig_regs
};
inj_ctx.target().write_regs(regs)?;
let orig_regs = inj_ctx.target().main_thread()?.read_regs()?;
println!("orig rip: {:016x}", orig_regs.ip());

let mut regs = orig_regs.clone();
regs.set_ip(run_function);
regs.set_sp(stack);
inj_ctx.target().main_thread()?.write_regs(regs)?;

let status = inj_ctx.target().unpause()?;
println!(
"{:?} at 0x{:016x}",
status,
inj_ctx.target().read_regs()?.rip
inj_ctx.target().main_thread()?.read_regs()?.ip()
);
inj_ctx.target().write_regs(orig_regs)?;
inj_ctx.target().main_thread()?.write_regs(orig_regs)?;

Ok(())
}
Expand Down
4 changes: 4 additions & 0 deletions src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ mod windows;
#[cfg(target_os = "windows")]
pub use windows::*;

mod registers;
mod thread;

pub use registers::Registers;
pub use thread::Thread;

#[derive(Debug)]
pub struct MemoryMap {
/// Start and end range of the mapped memory.
Expand Down
Loading