pub fn is_gadget_tail(instr: &iced_x86::Instruction) -> bool {
is_rop_gadget_tail(instr) || is_jop_gadget_tail(instr) || is_sys_gadget_tail(instr)
}
pub fn is_rop_gadget_tail(instr: &iced_x86::Instruction) -> bool {
is_ret(instr, true)
}
pub fn is_jop_gadget_tail(instr: &iced_x86::Instruction) -> bool {
is_indirect_call(instr) || is_indirect_jmp(instr)
}
pub fn is_sys_gadget_tail(instr: &iced_x86::Instruction) -> bool {
is_syscall(instr) || is_sysret(instr)
}
pub fn is_gadget_body(instr: &iced_x86::Instruction, all: bool) -> bool {
let instr_flow = instr.flow_control();
if instr_flow == iced_x86::FlowControl::Exception {
return false;
}
if !all {
if matches!(
instr_flow,
iced_x86::FlowControl::UnconditionalBranch
| iced_x86::FlowControl::ConditionalBranch
| iced_x86::FlowControl::Call
| iced_x86::FlowControl::Return
| iced_x86::FlowControl::Interrupt
) {
return false;
}
if instr.has_rep_prefix() || instr.has_repe_prefix() || instr.has_repne_prefix() {
return false;
}
}
!is_gadget_tail(instr)
}
pub fn is_indirect_call(instr: &iced_x86::Instruction) -> bool {
(instr.flow_control() == iced_x86::FlowControl::IndirectCall) && (is_reg_ops_only(instr))
}
pub fn is_indirect_jmp(instr: &iced_x86::Instruction) -> bool {
(instr.flow_control() == iced_x86::FlowControl::IndirectBranch) && (is_reg_ops_only(instr))
}
pub fn is_syscall(instr: &iced_x86::Instruction) -> bool {
match instr.mnemonic() {
iced_x86::Mnemonic::Int => matches!(instr.try_immediate(0), Ok(0x80) | Ok(0x2e)),
iced_x86::Mnemonic::Syscall | iced_x86::Mnemonic::Sysenter => true,
_ => false,
}
}
pub fn is_sysret(instr: &iced_x86::Instruction) -> bool {
matches!(
instr.mnemonic(),
iced_x86::Mnemonic::Iret
| iced_x86::Mnemonic::Iretd
| iced_x86::Mnemonic::Iretq
| iced_x86::Mnemonic::Sysexit
| iced_x86::Mnemonic::Sysexitq
| iced_x86::Mnemonic::Sysret
| iced_x86::Mnemonic::Sysretq
)
}
pub fn is_ret(instr: &iced_x86::Instruction, all: bool) -> bool {
if !matches!(
instr.mnemonic(),
iced_x86::Mnemonic::Ret | iced_x86::Mnemonic::Retf
) {
return false;
}
if (!all) && (instr.op_count() > 0) {
return false;
}
true
}
pub fn is_reg_rw(instr: &iced_x86::Instruction, reg: &iced_x86::Register) -> bool {
let mut info_factory = iced_x86::InstructionInfoFactory::new();
let info = info_factory.info_options(instr, iced_x86::InstructionInfoOptions::NO_MEMORY_USAGE);
let reg_rw = iced_x86::UsedRegister::new(*reg, iced_x86::OpAccess::ReadWrite);
info.used_registers().contains(®_rw)
}
pub fn is_reg_set(instr: &iced_x86::Instruction, reg: &iced_x86::Register) -> bool {
let mut info_factory = iced_x86::InstructionInfoFactory::new();
let info = info_factory.info_options(instr, iced_x86::InstructionInfoOptions::NO_MEMORY_USAGE);
let reg_w = iced_x86::UsedRegister::new(*reg, iced_x86::OpAccess::Write);
if info.used_registers().iter().any(|ur| {
matches!(
ur.access(),
iced_x86::OpAccess::Read | iced_x86::OpAccess::ReadWrite
)
}) && info.used_registers().contains(®_w)
{
return true;
}
false
}
pub fn is_reg_ops_only(instr: &iced_x86::Instruction) -> bool {
let op_cnt = instr.op_count();
for op_idx in 0..op_cnt {
match instr.try_op_kind(op_idx) {
Ok(kind) => match kind {
iced_x86::OpKind::Register => {}
iced_x86::OpKind::Memory => {
if matches!(
instr.memory_base(),
iced_x86::Register::None
| iced_x86::Register::EIP
| iced_x86::Register::RIP
) {
return false;
}
}
_ => return false,
},
_ => return false,
}
}
op_cnt > 0
}