Skip to content

Commit aef686f

Browse files
authored
Merge pull request #20 from icicle-emu/x86-eflags-hook
X86 eflags hook
2 parents 7a09564 + 556eb71 commit aef686f

File tree

2 files changed

+83
-6
lines changed

2 files changed

+83
-6
lines changed

src/lib.rs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,36 @@
11
use std::borrow::Cow;
22
use std::collections::HashMap;
33
use icicle_cpu::mem::{Mapping, MemError, perm};
4-
use icicle_cpu::{ExceptionCode, VmExit};
4+
use icicle_cpu::{Cpu, ExceptionCode, ValueSource, VarSource, VmExit};
55
use pyo3::prelude::*;
66
use icicle_vm;
7-
use icicle_vm::linux::LinuxCpu;
87
use pyo3::exceptions::*;
98
use target_lexicon;
109
use indexmap::IndexMap;
10+
use target_lexicon::Architecture;
11+
use icicle_cpu::lifter::InstructionSource;
1112
use sleigh_runtime::NamedRegister;
1213

1314
// References:
1415
// - https://pyo3.rs/main/conversions/tables
1516
// - https://pyo3.rs/main/class
1617

18+
struct X86FlagsRegHandler {
19+
pub eflags: pcode::VarNode,
20+
}
21+
22+
impl icicle_cpu::RegHandler for X86FlagsRegHandler {
23+
fn read(&mut self, cpu: &mut Cpu) {
24+
let eflags = icicle_vm::x86::eflags(cpu);
25+
cpu.write_var::<u32>(self.eflags, eflags);
26+
}
27+
28+
fn write(&mut self, cpu: &mut Cpu) {
29+
let eflags = cpu.read_var::<u32>(self.eflags);
30+
icicle_vm::x86::set_eflags(cpu, eflags);
31+
}
32+
}
33+
1734
#[pyclass(eq, eq_int, module = "icicle")]
1835
#[derive(Clone, Debug, PartialEq)]
1936
pub enum MemoryProtection {
@@ -227,7 +244,7 @@ pub struct Icicle {
227244
}
228245

229246
fn reg_find<'a>(i: &'a Icicle, name: &str) -> PyResult<&'a NamedRegister> {
230-
let sleigh = i.vm.cpu.sleigh();
247+
let sleigh = &i.vm.cpu.arch.sleigh;
231248
match sleigh.get_reg(name) {
232249
None => {
233250
i.regs.get(name.to_lowercase().as_str())
@@ -354,19 +371,29 @@ impl Icicle {
354371
config.optimize_instructions = optimize_instructions;
355372
config.optimize_block = optimize_block;
356373

357-
let vm = icicle_vm::build(&config)
374+
let mut vm = icicle_vm::build(&config)
358375
.map_err(|e| {
359376
PyException::new_err(format!("VM build error: {e}"))
360377
})?;
361378

362379
// Populate the lowercase register map
363380
let mut regs = HashMap::new();
364-
let sleigh = vm.cpu.sleigh();
381+
let sleigh = &vm.cpu.arch.sleigh;
365382
for reg in &sleigh.named_registers {
366383
let name = sleigh.get_str(reg.name);
367384
regs.insert(name.to_lowercase(), reg.clone());
368385
}
369386

387+
// Special handling for x86 flags
388+
match config.triple.architecture {
389+
Architecture::X86_32(_) | Architecture::X86_64 | Architecture::X86_64h => {
390+
let eflags = sleigh.get_reg("eflags").unwrap().var;
391+
let reg_handler = X86FlagsRegHandler { eflags };
392+
vm.cpu.add_reg_handler(eflags.id, Box::new(reg_handler));
393+
}
394+
_ => {}
395+
}
396+
370397
Ok(Icicle {
371398
architecture,
372399
vm,
@@ -454,7 +481,7 @@ impl Icicle {
454481

455482
pub fn reg_list(&self) -> PyResult<IndexMap<String, (u32, u8)>> {
456483
let mut result = IndexMap::new();
457-
let sleigh = self.vm.cpu.sleigh();
484+
let sleigh = &self.vm.cpu.arch.sleigh;
458485
for reg in &sleigh.named_registers {
459486
let name = sleigh.get_str(reg.name);
460487
result.insert(name.to_string(), (reg.offset, reg.var.size));

tests/tests.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,55 @@ fn step_modify_rip() -> PyResult<()> {
206206
Ok(())
207207
}
208208

209+
fn eflags_reconstruction() -> PyResult<()> {
210+
let mut vm = new_vm(false)?;
211+
vm.mem_map(0x100, 0x20, MemoryProtection::ExecuteRead)?;
212+
213+
vm.mem_write(0x100, b"\x48\x01\xD8".to_vec())?;
214+
vm.reg_write("rax", 0x7FFFFFFFFFFFFFFF)?;
215+
vm.reg_write("rbx", 0x1)?;
216+
217+
let of_mask = (1 << 11) as u64;
218+
219+
{
220+
let eflags = vm.reg_read("eflags")?;
221+
let of = vm.reg_read("OF")?;
222+
let of_set = (eflags & of_mask) == of_mask;
223+
println!("[pre] eflags: {:#x}, OF: {:#x} == {}", eflags, of, of_set);
224+
}
225+
226+
vm.set_pc(0x100);
227+
let status = vm.step(1);
228+
println!("run status: {:?}", status);
229+
230+
{
231+
let eflags = vm.reg_read("eflags")?;
232+
let rflags = vm.reg_read("rflags")?;
233+
let of = vm.reg_read("OF")?;
234+
let of_set = (eflags & of_mask) == of_mask;
235+
println!("[post] eflags: {:#x} == {:#x}, OF: {:#x} == {}", eflags, rflags, of, of_set);
236+
}
237+
238+
{
239+
vm.reg_write("OF", 0)?;
240+
let eflags = vm.reg_read("eflags")?;
241+
let of = vm.reg_read("OF")?;
242+
let of_set = (eflags >> 11) & 1;
243+
println!("[OF=0] eflags: {:#x}, OF: {:#x} == {}", eflags, of, of_set);
244+
}
245+
246+
{
247+
let mut eflags = vm.reg_read("eflags")?;
248+
eflags |= of_mask;
249+
vm.reg_write("rflags", eflags)?;
250+
let of = vm.reg_read("OF")?;
251+
let of_set = (eflags >> 11) & 1;
252+
println!("[rflags|={:#x}] eflags: {:#x}, OF: {:#x} == {}", of_mask, eflags, of, of_set);
253+
}
254+
255+
Ok(())
256+
}
257+
209258
fn main() {
210259
// Make sure the GHIDRA_SRC environment variable is valid
211260
match std::env::var("GHIDRA_SRC") {
@@ -236,6 +285,7 @@ fn main() {
236285
("Rewind", rewind),
237286
("Execute only", execute_only),
238287
("Step modify rip", step_modify_rip),
288+
("EFlags reconstruction", eflags_reconstruction),
239289
];
240290

241291
let mut success = 0;

0 commit comments

Comments
 (0)