nyx_lite/
disassembly.rs

1pub use iced_x86::OpAccess;
2use iced_x86::{
3    Decoder, DecoderOptions, FlowControl, Formatter, Instruction, InstructionInfoFactory,
4    NasmFormatter,
5};
6const HEXBYTES_COLUMN_BYTE_LENGTH: usize = 10;
7
8// slightly modifed from the iced_x86 example - note this function is incredibly poorly done from a performance perspective!
9pub fn disassemble(addr: u64, bytes: &[u8]) -> Vec<String> {
10    let wordsize = 64;
11    let mut decoder = Decoder::with_ip(wordsize, bytes, addr, DecoderOptions::NONE);
12
13    // Formatters: Masm*, Nasm*, Gas* (AT&T) and Intel* (XED).
14    // For fastest code, see `SpecializedFormatter` which is ~3.3x faster. Use it if formatting
15    // speed is more important than being able to re-assemble formatted instructions.
16    let mut formatter = NasmFormatter::new();
17
18    // Change some options, there are many more
19    formatter.options_mut().set_digit_separator("`");
20    formatter.options_mut().set_first_operand_char_index(10);
21
22    // Initialize this outside the loop because decode_out() writes to every field
23    let mut instruction = Instruction::default();
24
25    // The decoder also implements Iterator/IntoIterator so you could use a for loop:
26    //      for instruction in &mut decoder { /* ... */ }
27    // or collect():
28    //      let instructions: Vec<_> = decoder.into_iter().collect();
29    // but can_decode()/decode_out() is a little faster:
30    let mut res = vec![];
31    while decoder.can_decode() {
32        // There's also a decode() method that returns an instruction but that also
33        // means it copies an instruction (40 bytes):
34        //     instruction = decoder.decode();
35        decoder.decode_out(&mut instruction);
36
37        let mut output = String::new();
38        formatter.format(&instruction, &mut output);
39
40        // Eg. "00007FFAC46ACDB2 488DAC2400FFFFFF     lea       rbp,[rsp-100h]"
41        let mut prefix = format!("{:016X} ", instruction.ip());
42        let start_index = (instruction.ip() - addr) as usize;
43        let instr_bytes = &bytes[start_index..start_index + instruction.len()];
44        for b in instr_bytes.iter() {
45            prefix.push_str(&format!("{:02X}", b));
46        }
47        if instr_bytes.len() < HEXBYTES_COLUMN_BYTE_LENGTH {
48            for _ in 0..HEXBYTES_COLUMN_BYTE_LENGTH - instr_bytes.len() {
49                prefix.push_str("  ");
50            }
51        }
52        prefix.push_str(&output);
53        res.push(prefix);
54    }
55    return res;
56}
57
58pub fn disassemble_print(addr: u64, bytes: &[u8]) {
59    for line in disassemble(addr, bytes) {
60        println!("{}", line);
61    }
62}
63
64use iced_x86::Register;
65use kvm_bindings::{kvm_regs, kvm_sregs};
66
67fn get_register_value(reg: Register, regs: &kvm_regs, sregs: &kvm_sregs) -> u64 {
68    match reg {
69        Register::None => 0,
70        // 64-bit general purpose registers
71        Register::RAX => regs.rax,
72        Register::RBX => regs.rbx,
73        Register::RCX => regs.rcx,
74        Register::RDX => regs.rdx,
75        Register::RSI => regs.rsi,
76        Register::RDI => regs.rdi,
77        Register::RBP => regs.rbp,
78        Register::RSP => regs.rsp,
79        Register::R8 => regs.r8,
80        Register::R9 => regs.r9,
81        Register::R10 => regs.r10,
82        Register::R11 => regs.r11,
83        Register::R12 => regs.r12,
84        Register::R13 => regs.r13,
85        Register::R14 => regs.r14,
86        Register::R15 => regs.r15,
87        Register::RIP => regs.rip,
88
89        // 32-bit variants
90        Register::EAX => regs.rax as u32 as u64,
91        Register::EBX => regs.rbx as u32 as u64,
92        Register::ECX => regs.rcx as u32 as u64,
93        Register::EDX => regs.rdx as u32 as u64,
94        Register::ESI => regs.rsi as u32 as u64,
95        Register::EDI => regs.rdi as u32 as u64,
96        Register::EBP => regs.rbp as u32 as u64,
97        Register::ESP => regs.rsp as u32 as u64,
98        Register::R8D => regs.r8 as u32 as u64,
99        Register::R9D => regs.r9 as u32 as u64,
100        Register::R10D => regs.r10 as u32 as u64,
101        Register::R11D => regs.r11 as u32 as u64,
102        Register::R12D => regs.r12 as u32 as u64,
103        Register::R13D => regs.r13 as u32 as u64,
104        Register::R14D => regs.r14 as u32 as u64,
105        Register::R15D => regs.r15 as u32 as u64,
106        Register::EIP => regs.rip as u32 as u64,
107
108        // 16-bit variants
109        Register::AX => (regs.rax & 0xFFFF) as u64,
110        Register::BX => (regs.rbx & 0xFFFF) as u64,
111        Register::CX => (regs.rcx & 0xFFFF) as u64,
112        Register::DX => (regs.rdx & 0xFFFF) as u64,
113        Register::SI => (regs.rsi & 0xFFFF) as u64,
114        Register::DI => (regs.rdi & 0xFFFF) as u64,
115        Register::BP => (regs.rbp & 0xFFFF) as u64,
116        Register::SP => (regs.rsp & 0xFFFF) as u64,
117        Register::R8W => (regs.r8 & 0xFFFF) as u64,
118        Register::R9W => (regs.r9 & 0xFFFF) as u64,
119        Register::R10W => (regs.r10 & 0xFFFF) as u64,
120        Register::R11W => (regs.r11 & 0xFFFF) as u64,
121        Register::R12W => (regs.r12 & 0xFFFF) as u64,
122        Register::R13W => (regs.r13 & 0xFFFF) as u64,
123        Register::R14W => (regs.r14 & 0xFFFF) as u64,
124        Register::R15W => (regs.r15 & 0xFFFF) as u64,
125
126        // 8-bit variants (low)
127        Register::AL => (regs.rax & 0xFF) as u64,
128        Register::BL => (regs.rbx & 0xFF) as u64,
129        Register::CL => (regs.rcx & 0xFF) as u64,
130        Register::DL => (regs.rdx & 0xFF) as u64,
131        Register::SIL => (regs.rsi & 0xFF) as u64,
132        Register::DIL => (regs.rdi & 0xFF) as u64,
133        Register::BPL => (regs.rbp & 0xFF) as u64,
134        Register::SPL => (regs.rsp & 0xFF) as u64,
135        Register::R8L => (regs.r8 & 0xFF) as u64,
136        Register::R9L => (regs.r9 & 0xFF) as u64,
137        Register::R10L => (regs.r10 & 0xFF) as u64,
138        Register::R11L => (regs.r11 & 0xFF) as u64,
139        Register::R12L => (regs.r12 & 0xFF) as u64,
140        Register::R13L => (regs.r13 & 0xFF) as u64,
141        Register::R14L => (regs.r14 & 0xFF) as u64,
142        Register::R15L => (regs.r15 & 0xFF) as u64,
143
144        // 8-bit variants (high)
145        Register::AH => ((regs.rax >> 8) & 0xFF) as u64,
146        Register::BH => ((regs.rbx >> 8) & 0xFF) as u64,
147        Register::CH => ((regs.rcx >> 8) & 0xFF) as u64,
148        Register::DH => ((regs.rdx >> 8) & 0xFF) as u64,
149        // Segment registers
150        Register::CS => sregs.cs.base,
151        Register::DS => sregs.ds.base,
152        Register::SS => sregs.ss.base,
153        Register::ES => sregs.es.base,
154        Register::FS => sregs.fs.base,
155        Register::GS => sregs.gs.base,
156
157        // Default case for unsupported registers
158        reg => panic!("unhandled memory access with register {:?}", reg),
159    }
160}
161
162// Assume this exists in your code
163pub fn get_memory_accesses(
164    instr: &Instruction,
165    regs: &kvm_regs,
166    sregs: &kvm_sregs,
167) -> Vec<(u64, OpAccess)> {
168    let mut factory = InstructionInfoFactory::new();
169    let info = factory.info(instr);
170    let page_size = crate::mem::PAGE_SIZE;
171    let page_mask = !(page_size - 1);
172    let mut accesses = Vec::new();
173    for mem in info.used_memory().iter() {
174        let base = get_register_value(mem.base(), regs, sregs) as i128;
175        let index = get_register_value(mem.index(), regs, sregs) as i128;
176        let scale = mem.scale() as i128;
177        let displacement = mem.displacement() as i128;
178        let segment = get_register_value(mem.segment(), regs, sregs) as i128;
179
180        let addr = (segment + base + (index * scale) + displacement) as u64;
181        let access = mem.access();
182        accesses.push((addr, access));
183
184        let size_bytes = mem.memory_size().size();
185        if size_bytes == 0 {
186            continue;
187        }
188        let end = addr.saturating_add(size_bytes as u64 - 1);
189        let mut next_page = (addr & page_mask).saturating_add(page_size);
190        while next_page <= end {
191            accesses.push((next_page, access));
192            next_page = next_page.saturating_add(page_size);
193        }
194    }
195    accesses
196}
197
198pub fn disassemble_memory_accesses(
199    data: &[u8],
200    regs: &kvm_regs,
201    sregs: &kvm_sregs,
202) -> Vec<(u64, OpAccess)> {
203    let mut decoder = Decoder::with_ip(64, data, regs.rip, DecoderOptions::NONE);
204    let mut instruction = Instruction::default();
205    if decoder.can_decode() {
206        decoder.decode_out(&mut instruction);
207    } else {
208        return vec![];
209    }
210    return get_memory_accesses(&instruction, regs, sregs);
211}
212
213pub fn is_control_flow(addr: u64, bytes: &[u8]) -> bool {
214    let mut decoder = Decoder::with_ip(64, bytes, addr, DecoderOptions::NONE);
215    let mut instruction = Instruction::default();
216    if !decoder.can_decode() {
217        return false;
218    }
219    decoder.decode_out(&mut instruction);
220    !matches!(instruction.flow_control(), FlowControl::Next)
221}