use std::{ffi::CString, fmt::Write, mem};
use zydis::{ffi::DecodedOperandKind, *};
#[rustfmt::skip]
static CODE: &[u8] = &[
0x0F, 0xC2, 0xCC, 0x03,
0xC5, 0xE9, 0xC2, 0xCB, 0x17,
0x62, 0xF1, 0x6C, 0x5F, 0xC2, 0x54, 0x98, 0x40, 0x0F
];
static CONDITION_CODES: &[&str] = &[
"eq", "lt", "le", "unord", "neq", "nlt", "nle", "ord", "eq_uq", "nge", "ngt", "false", "oq",
"ge", "gt", "true", "eq_os", "lt_oq", "le_oq", "unord_s", "neq_us", "nlt_uq", "nle_uq",
"ord_s", "eq_us", "nge_uq", "ngt_uq", "false_os", "neg_os", "ge_oq", "gt_oq", "true_us",
];
fn user_err<T>(_: T) -> Status {
Status::User
}
struct UserData {
orig_print_mnemonic: Hook,
orig_format_operand: Hook,
omit_immediate: bool,
}
fn print_mnemonic(
formatter: &Formatter<UserData>,
buffer: &mut ffi::FormatterBuffer,
ctx: &mut ffi::FormatterContext,
user_data: Option<&mut UserData>,
) -> Result<()> {
let instruction = unsafe { &*ctx.instruction };
let operands =
unsafe { core::slice::from_raw_parts(ctx.operands, instruction.operand_count as usize) };
let user_data = user_data.unwrap();
if let Hook::PrintMnemonic(orig_print_mnemonic) = user_data.orig_print_mnemonic {
user_data.omit_immediate = true;
let count = instruction.operand_count as usize;
if count > 0 {
if let DecodedOperandKind::Imm(imm) = &operands[count - 1].kind {
let cc = imm.value as usize;
match instruction.mnemonic {
Mnemonic::CMPPS if cc < 8 => {
buffer.append(TOKEN_MNEMONIC)?;
let string = buffer.get_string()?;
return write!(string, "cmp{}ps", CONDITION_CODES[cc]).map_err(user_err);
}
Mnemonic::CMPPD if cc < 8 => {
buffer.append(TOKEN_MNEMONIC)?;
let string = buffer.get_string()?;
return write!(string, "cmp{}pd", CONDITION_CODES[cc]).map_err(user_err);
}
Mnemonic::VCMPPS if cc < 0x20 => {
buffer.append(TOKEN_MNEMONIC)?;
let string = buffer.get_string()?;
return write!(string, "vcmp{}ps", CONDITION_CODES[cc]).map_err(user_err);
}
Mnemonic::VCMPPD if cc < 0x20 => {
buffer.append(TOKEN_MNEMONIC)?;
let string = buffer.get_string()?;
return write!(string, "vcmp{}pd", CONDITION_CODES[cc]).map_err(user_err);
}
_ => {}
}
}
}
user_data.omit_immediate = false;
unsafe { orig_print_mnemonic(mem::transmute(formatter), buffer, ctx).into() }
} else {
Ok(())
}
}
fn format_operand_imm(
formatter: &Formatter<UserData>,
buffer: &mut ffi::FormatterBuffer,
ctx: &mut ffi::FormatterContext,
user_data: Option<&mut UserData>,
) -> Result<()> {
let user_data = user_data.unwrap();
if let Hook::FormatOperandImm(orig_format_operand) = user_data.orig_format_operand {
if user_data.omit_immediate {
Err(Status::SkipToken)
} else {
unsafe { orig_format_operand(mem::transmute(formatter), buffer, ctx).as_result() }
}
} else {
Ok(())
}
}
fn main() -> Result<()> {
let s = CString::new("h").unwrap();
let mut formatter = Formatter::<UserData>::new_custom_userdata(FormatterStyle::INTEL);
formatter.set_property(FormatterProperty::ForceSegment(true))?;
formatter.set_property(FormatterProperty::ForceSize(true))?;
formatter.set_property(FormatterProperty::HexPrefix(None))?;
formatter.set_property(FormatterProperty::HexSuffix(Some(s.as_c_str())))?;
let decoder = Decoder::new64();
let mut buffer = [0u8; 200];
let mut buffer = OutputBuffer::new(&mut buffer[..]);
for item in decoder.decode_all::<VisibleOperands>(CODE, 0) {
let (ip, _, insn) = item?;
formatter.format_ex(Some(ip), &insn, &mut buffer, None)?;
println!("0x{:016X} {}", ip, buffer);
}
println!();
let orig_print_mnemonic = formatter.set_print_mnemonic(Box::new(print_mnemonic))?;
let orig_format_operand = formatter.set_format_operand_imm(Box::new(format_operand_imm))?;
let mut user_data = UserData {
orig_print_mnemonic,
orig_format_operand,
omit_immediate: false,
};
for item in decoder.decode_all::<VisibleOperands>(CODE, 0) {
let (ip, _, insn) = item?;
formatter.format_ex(Some(ip), &insn, &mut buffer, Some(&mut user_data))?;
println!("0x{:016X} {}", ip, buffer);
}
Ok(())
}