nyx_lite/
breakpoints.rs

1use std::collections::BTreeMap;
2
3use vmm::Vmm;
4
5use crate::mem::NyxMemExtension;
6
7pub struct Breakpoint {
8    pub cr3: u64,
9    pub vaddr: u64,
10    pub orig_val: Option<u8>,
11    pub enabled: bool,
12}
13
14impl Breakpoint {
15    pub fn new(cr3: u64, vaddr: u64) -> Self {
16        return Self {
17            cr3,
18            vaddr,
19            orig_val: None,
20            enabled: false,
21        };
22    }
23}
24
25// A trait so users can define their own logic for deciding which breakpoints to handle.
26pub trait BreakpointManagerTrait {
27    // should we forward the current breakpoint to the guest rather than handle it ourselfs?
28    fn known_breakpoint(&self, cr3: u64, rip: u64) -> bool;
29    fn disable_all_breakpoints(&mut self, vmm: &mut Vmm);
30    fn enable_all_breakpoints(&mut self, vmm: &mut Vmm);
31    fn disable_breakpoint(&mut self, vmm: &mut Vmm, _cr3: u64, _vaddr: u64) {
32        self.disable_all_breakpoints(vmm);
33    }
34    fn enable_breakpoint(&mut self, vmm: &mut Vmm, _cr3: u64, _vaddr: u64) {
35        self.enable_all_breakpoints(vmm);
36    }
37    fn add_breakpoint(&mut self, cr3: u64, vaddr: u64);
38    fn remove_breakpoint(&mut self, cr3: u64, vaddr: u64);
39    fn remove_all_breakpoints(&mut self);
40
41    fn forward_guest_bp(&self, cr3: u64, rip: u64) -> bool {
42        return !self.known_breakpoint(cr3, rip);
43    }
44}
45
46pub struct BreakpointManager {
47    pub breakpoints: BTreeMap<(u64, u64), Breakpoint>,
48    all_enabled: bool,
49}
50
51impl BreakpointManager {
52    pub fn new() -> Self {
53        return Self {
54            breakpoints: BTreeMap::new(),
55            all_enabled: false,
56        };
57    }
58}
59
60impl BreakpointManagerTrait for BreakpointManager {
61    fn known_breakpoint(&self, cr3: u64, rip: u64) -> bool {
62        let known_bp = self.breakpoints.contains_key(&(cr3, rip));
63        return known_bp;
64    }
65    fn disable_all_breakpoints(&mut self, vmm: &mut Vmm) {
66        for bp in self.breakpoints.values_mut() {
67            if !bp.enabled {
68                continue;
69            }
70            vmm.write_virtual_u8(bp.cr3, bp.vaddr, bp.orig_val.unwrap())
71                .unwrap();
72            bp.enabled = false;
73        }
74        self.all_enabled = false;
75    }
76    fn enable_all_breakpoints(&mut self, vmm: &mut Vmm) {
77        if self.all_enabled {
78            return;
79        }
80        for bp in self.breakpoints.values_mut() {
81            if bp.enabled {
82                continue;
83            }
84            if bp.orig_val.is_none() {
85                bp.orig_val = Some(vmm.read_virtual_u8(bp.cr3, bp.vaddr).unwrap());
86            }
87            vmm.write_virtual_u8(bp.cr3, bp.vaddr, 0xcc).unwrap();
88            bp.enabled = true;
89        }
90        self.all_enabled = true;
91    }
92    fn disable_breakpoint(&mut self, vmm: &mut Vmm, cr3: u64, vaddr: u64) {
93        if let Some(bp) = self.breakpoints.get_mut(&(cr3, vaddr)) {
94            if bp.enabled {
95                vmm.write_virtual_u8(bp.cr3, bp.vaddr, bp.orig_val.unwrap())
96                    .unwrap();
97                bp.enabled = false;
98                self.all_enabled = false;
99            }
100        }
101    }
102    fn enable_breakpoint(&mut self, vmm: &mut Vmm, cr3: u64, vaddr: u64) {
103        if let Some(bp) = self.breakpoints.get_mut(&(cr3, vaddr)) {
104            if !bp.enabled {
105                if bp.orig_val.is_none() {
106                    bp.orig_val = Some(vmm.read_virtual_u8(bp.cr3, bp.vaddr).unwrap());
107                }
108                vmm.write_virtual_u8(bp.cr3, bp.vaddr, 0xcc).unwrap();
109                bp.enabled = true;
110            }
111        }
112    }
113
114    fn add_breakpoint(&mut self, cr3: u64, vaddr: u64) {
115        let breakpoint = Breakpoint::new(cr3, vaddr);
116        self.breakpoints.insert((cr3, vaddr), breakpoint);
117        self.all_enabled = false;
118    }
119
120    fn remove_breakpoint(&mut self, cr3: u64, vaddr: u64) {
121        self.breakpoints.remove(&(cr3, vaddr));
122        self.all_enabled = false;
123    }
124    fn remove_all_breakpoints(&mut self) {
125        self.breakpoints.clear();
126        self.all_enabled = false;
127    }
128}