use iced_x86::{Code, FlowControl, Instruction, Mnemonic, OpKind, Register};
fn is_ret(instr: &Instruction) -> bool { matches!(instr.mnemonic(), Mnemonic::Ret) }
fn is_sys(instr: &Instruction) -> bool {
match instr.mnemonic() {
Mnemonic::Syscall => true,
Mnemonic::Int => matches!(instr.try_immediate(0).unwrap(), 0x80),
Mnemonic::Iret | Mnemonic::Iretd | Mnemonic::Iretq => true,
Mnemonic::Sysret | Mnemonic::Sysretq | Mnemonic::Sysexit | Mnemonic::Sysexitq => true,
_ => false,
}
}
fn is_jop(instr: &Instruction, noisy: bool) -> bool {
match instr.mnemonic() {
Mnemonic::Jmp => {
if noisy {
!matches!(
instr.op0_kind(),
OpKind::NearBranch64 | OpKind::NearBranch32 | OpKind::NearBranch16
)
}
else {
match instr.op0_kind() {
OpKind::Register => true,
OpKind::Memory => !matches!(instr.memory_base(), Register::EIP | Register::RIP),
_ => false,
}
}
}
Mnemonic::Call => {
if noisy {
!matches!(
instr.op0_kind(),
OpKind::NearBranch64 | OpKind::NearBranch32 | OpKind::NearBranch16
)
}
else {
match instr.op0_kind() {
OpKind::Register => true,
OpKind::Memory => !matches!(instr.memory_base(), Register::EIP | Register::RIP),
_ => false,
}
}
}
_ => false,
}
}
fn is_invalid(instr: &Instruction) -> bool { matches!(instr.code(), Code::INVALID) }
pub fn is_gadget_tail(instr: &Instruction, rop: bool, sys: bool, jop: bool, noisy: bool) -> bool {
if is_invalid(instr) {
return false;
}
if instr.flow_control() == FlowControl::Next {
return false;
}
if rop && is_ret(instr) {
return true;
}
if sys && is_sys(instr) {
return true;
}
if jop && is_jop(instr, noisy) {
return true;
}
false
}
pub fn is_rop_gadget_head(instr: &Instruction, noisy: bool) -> bool {
if is_invalid(instr) {
return false;
}
if !noisy
&& (instr.has_lock_prefix()
|| instr.has_rep_prefix()
|| instr.has_repe_prefix()
|| instr.has_repne_prefix()
|| instr.has_xacquire_prefix()
|| instr.has_xrelease_prefix())
{
return false;
}
match instr.flow_control() {
FlowControl::Next | FlowControl::Interrupt => true,
FlowControl::ConditionalBranch => noisy,
FlowControl::Call => instr.mnemonic() != Mnemonic::Call,
_ => false,
}
}
pub fn is_stack_pivot_head(instr: &Instruction) -> bool {
let reg0 = instr.op0_register();
let kind1 = instr.op1_kind();
let reg1 = instr.op1_register();
match instr.mnemonic() {
Mnemonic::Adc
| Mnemonic::Adcx
| Mnemonic::Add
| Mnemonic::Sbb
| Mnemonic::Sub
| Mnemonic::Bndmov
| Mnemonic::Cmova
| Mnemonic::Cmovae
| Mnemonic::Cmovb
| Mnemonic::Cmovbe
| Mnemonic::Cmove
| Mnemonic::Cmovg
| Mnemonic::Cmovge
| Mnemonic::Cmovl
| Mnemonic::Cmovle
| Mnemonic::Cmovne
| Mnemonic::Cmovno
| Mnemonic::Cmovnp
| Mnemonic::Cmovns
| Mnemonic::Cmovo
| Mnemonic::Cmovp
| Mnemonic::Cmovs
| Mnemonic::Cmpxchg
| Mnemonic::Cmpxchg16b
| Mnemonic::Cmpxchg8b
| Mnemonic::Pop
| Mnemonic::Popa
| Mnemonic::Popad => {
matches!(reg0, Register::RSP | Register::ESP | Register::SP)
&& matches!(
kind1,
OpKind::Immediate8
| OpKind::Immediate8_2nd | OpKind::Immediate16
| OpKind::Immediate32 | OpKind::Immediate64
| OpKind::Immediate8to16 | OpKind::Immediate8to32
| OpKind::Immediate8to64 | OpKind::Immediate32to64
| OpKind::Register
)
}
Mnemonic::Mov | Mnemonic::Movbe | Mnemonic::Movd => {
matches!(reg0, Register::RSP | Register::ESP | Register::SP)
&& (matches!(kind1, OpKind::Register) || instr.memory_base() != Register::None)
}
Mnemonic::Xadd | Mnemonic::Xchg => {
matches!(reg0, Register::RSP | Register::ESP | Register::SP)
|| matches!(reg1, Register::RSP | Register::ESP | Register::SP)
}
Mnemonic::Leave => true,
_ => false,
}
}
pub fn is_stack_pivot_tail(instr: &Instruction) -> bool { is_ret(instr) }
pub fn is_base_pivot_head(instr: &Instruction) -> bool {
let reg0 = instr.op0_register();
let kind1 = instr.op1_kind();
let reg1 = instr.op1_register();
match instr.mnemonic() {
Mnemonic::Adc
| Mnemonic::Adcx
| Mnemonic::Add
| Mnemonic::Sbb
| Mnemonic::Sub
| Mnemonic::Bndmov
| Mnemonic::Cmova
| Mnemonic::Cmovae
| Mnemonic::Cmovb
| Mnemonic::Cmovbe
| Mnemonic::Cmove
| Mnemonic::Cmovg
| Mnemonic::Cmovge
| Mnemonic::Cmovl
| Mnemonic::Cmovle
| Mnemonic::Cmovne
| Mnemonic::Cmovno
| Mnemonic::Cmovnp
| Mnemonic::Cmovns
| Mnemonic::Cmovo
| Mnemonic::Cmovp
| Mnemonic::Cmovs
| Mnemonic::Cmpxchg
| Mnemonic::Cmpxchg16b
| Mnemonic::Cmpxchg8b
| Mnemonic::Pop
| Mnemonic::Popa
| Mnemonic::Popad => {
matches!(reg0, Register::RBP | Register::EBP | Register::BP)
&& matches!(
kind1,
OpKind::Immediate8
| OpKind::Immediate8_2nd | OpKind::Immediate16
| OpKind::Immediate32 | OpKind::Immediate64
| OpKind::Immediate8to16 | OpKind::Immediate8to32
| OpKind::Immediate8to64 | OpKind::Immediate32to64
| OpKind::Register
)
}
Mnemonic::Mov | Mnemonic::Movbe | Mnemonic::Movd => {
matches!(reg0, Register::RBP | Register::EBP | Register::BP)
&& (matches!(kind1, OpKind::Register) || instr.memory_base() != Register::None)
}
Mnemonic::Xadd | Mnemonic::Xchg => {
matches!(reg0, Register::RBP | Register::EBP | Register::BP)
|| matches!(reg1, Register::RBP | Register::EBP | Register::BP)
}
Mnemonic::Enter => true,
_ => false,
}
}