Skip to content

Commit 3a01515

Browse files
authored
Rust Bindings: reg_read_batch and reg_write_batch (#2060)
* Added binding for rust reg_{read,write}_batch * Fix reg_write_batch values pointer
1 parent 7d8fe2a commit 3a01515

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

bindings/rust/src/ffi.rs

+12
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,19 @@ extern "C" {
2323
pub fn uc_errno(engine: uc_handle) -> uc_error;
2424
pub fn uc_strerror(error_code: uc_error) -> *const c_char;
2525
pub fn uc_reg_write(engine: uc_handle, regid: c_int, value: *const c_void) -> uc_error;
26+
pub fn uc_reg_write_batch(
27+
engine: uc_handle,
28+
regids: *const c_int,
29+
values: *const *const c_void,
30+
count: c_int,
31+
) -> uc_error;
2632
pub fn uc_reg_read(engine: uc_handle, regid: c_int, value: *mut c_void) -> uc_error;
33+
pub fn uc_reg_read_batch(
34+
engine: uc_handle,
35+
regids: *const c_int,
36+
values: *const *mut c_void,
37+
count: c_int,
38+
) -> uc_error;
2739
pub fn uc_mem_write(
2840
engine: uc_handle,
2941
address: u64,

bindings/rust/src/lib.rs

+49
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,28 @@ impl<'a, D> Unicorn<'a, D> {
523523
.into()
524524
}
525525

526+
/// Write values into batch of registers
527+
pub fn reg_write_batch<T: Into<i32>>(
528+
&self,
529+
regids: &[T],
530+
values: &[u64],
531+
count: i32,
532+
) -> Result<(), uc_error> {
533+
let mut values_ptrs: Vec<*const u64> = vec![0 as *const u64; count as usize];
534+
for i in 0..values.len() {
535+
values_ptrs[i as usize] = &values[i] as *const u64;
536+
}
537+
unsafe {
538+
ffi::uc_reg_write_batch(
539+
self.get_handle(),
540+
regids.as_ptr() as *const i32,
541+
values_ptrs.as_ptr() as *const *const c_void,
542+
count,
543+
)
544+
}
545+
.into()
546+
}
547+
526548
/// Write variable sized values into registers.
527549
///
528550
/// The user has to make sure that the buffer length matches the register size.
@@ -540,6 +562,33 @@ impl<'a, D> Unicorn<'a, D> {
540562
.and(Ok(value))
541563
}
542564

565+
/// Read batch of registers
566+
///
567+
/// Not to be used with registers larger than 64 bit
568+
pub fn reg_read_batch<T: Into<i32>>(
569+
&self,
570+
regids: &[T],
571+
count: i32,
572+
) -> Result<Vec<u64>, uc_error> {
573+
unsafe {
574+
let mut addrs_vec = vec![0u64; count as usize];
575+
let addrs = addrs_vec.as_mut_slice();
576+
for i in 0..count {
577+
addrs[i as usize] = &mut addrs[i as usize] as *mut u64 as u64;
578+
}
579+
let res = ffi::uc_reg_read_batch(
580+
self.get_handle(),
581+
regids.as_ptr() as *const i32,
582+
addrs.as_ptr() as *const *mut c_void,
583+
count,
584+
);
585+
match res {
586+
uc_error::OK => Ok(addrs_vec),
587+
_ => Err(res),
588+
}
589+
}
590+
}
591+
543592
/// Read 128, 256 or 512 bit register value into heap allocated byte array.
544593
///
545594
/// This adds safe support for registers >64 bit (GDTR/IDTR, XMM, YMM, ZMM, ST (x86); Q, V (arm64)).

tests/rust-tests/main.rs

+32
Original file line numberDiff line numberDiff line change
@@ -815,3 +815,35 @@ fn x86_tlb_callback() {
815815
assert_eq!(emu.remove_hook(tlb_hook), Ok(()));
816816
assert_eq!(emu.remove_hook(syscall_hook), Ok(()));
817817
}
818+
819+
#[test]
820+
fn x86_reg_rw_batch() {
821+
// mov rax, 0x10, mov rbx, 0x20, mov rcx, 0x30, mov rdx, 0x40
822+
let code: Vec<u8> = vec![0x48, 0xC7, 0xC0, 0x10, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC3, 0x20, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC1, 0x30, 0x00, 0x00, 0x00, 0x48, 0xC7, 0xC2, 0x40, 0x00, 0x00, 0x00];
823+
let expect: Vec<u64> = vec![0x10, 0x20, 0x30, 0x40];
824+
let mut emu = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_64)
825+
.expect("failed to initialize unicorn instance");
826+
assert_eq!(emu.mem_map(0x1000, 0x1000, Permission::ALL), Ok(()));
827+
assert_eq!(emu.mem_write(0x1000, &code), Ok(()));
828+
829+
assert_eq!(
830+
emu.emu_start(0x1000, (0x1000 + code.len()) as u64, 0, 0),
831+
Ok(())
832+
);
833+
834+
let regids = vec![RegisterX86::RAX, RegisterX86::RBX, RegisterX86::RCX, RegisterX86::RDX];
835+
assert_eq!(
836+
emu.reg_read_batch(&regids, 4),
837+
Ok(expect)
838+
);
839+
let regvals = vec![0x50, 0x60, 0x70, 0x80];
840+
assert_eq!(
841+
emu.reg_write_batch(&regids, &regvals, 4),
842+
Ok(())
843+
);
844+
assert_eq!(
845+
emu.reg_read_batch(&regids, 4),
846+
Ok(vec![0x50, 0x60, 0x70, 0x80])
847+
);
848+
849+
}

0 commit comments

Comments
 (0)