1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#[inline(always)]
pub fn is_gadget_tail(instr: &iced_x86::Instruction) -> bool {
is_ret(instr) || is_jop_gadget_tail(instr) || is_sys_gadget_tail(instr)
}
#[inline(always)]
pub fn is_jop_gadget_tail(instr: &iced_x86::Instruction) -> bool {
is_reg_indirect_call(instr) || is_reg_indirect_jmp(instr)
}
#[inline(always)]
pub fn is_sys_gadget_tail(instr: &iced_x86::Instruction) -> bool {
is_syscall(instr) || is_legacy_linux_syscall(instr)
}
#[inline(always)]
pub fn is_reg_indirect_call(instr: &iced_x86::Instruction) -> bool {
(instr.flow_control() == iced_x86::FlowControl::IndirectCall) && (has_ctrled_ops_only(instr))
}
#[inline(always)]
pub fn is_reg_indirect_jmp(instr: &iced_x86::Instruction) -> bool {
(instr.flow_control() == iced_x86::FlowControl::IndirectBranch) && (has_ctrled_ops_only(instr))
}
#[inline(always)]
pub fn is_ret(instr: &iced_x86::Instruction) -> bool {
(instr.mnemonic() == iced_x86::Mnemonic::Ret) || (instr.mnemonic() == iced_x86::Mnemonic::Retf)
}
#[inline(always)]
pub fn is_ret_imm16(instr: &iced_x86::Instruction) -> bool {
is_ret(instr) && (instr.op_count() != 0)
}
#[inline(always)]
pub fn is_direct_call(instr: &iced_x86::Instruction) -> bool {
(instr.mnemonic() == iced_x86::Mnemonic::Call) && (!is_reg_indirect_call(instr))
}
pub fn is_uncond_fixed_jmp(instr: &iced_x86::Instruction) -> bool {
(instr.mnemonic() == iced_x86::Mnemonic::Jmp) && (!is_reg_indirect_jmp(instr))
}
#[inline(always)]
pub fn is_int(instr: &iced_x86::Instruction) -> bool {
instr.flow_control() == iced_x86::FlowControl::Interrupt
}
#[inline(always)]
pub fn is_syscall(instr: &iced_x86::Instruction) -> bool {
(instr.mnemonic() == iced_x86::Mnemonic::Syscall)
|| (instr.mnemonic() == iced_x86::Mnemonic::Sysenter)
}
#[inline(always)]
pub fn is_legacy_linux_syscall(instr: &iced_x86::Instruction) -> bool {
match instr.try_immediate(0) {
Ok(imm) => (imm == 0x80) && (instr.mnemonic() == iced_x86::Mnemonic::Int),
_ => false,
}
}
#[inline(always)]
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)
}
#[inline(always)]
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);
let reg_read = |ur: iced_x86::UsedRegister| {
ur.access() == iced_x86::OpAccess::Read || ur.access() == iced_x86::OpAccess::ReadWrite
};
if info.used_registers().iter().any(|ur| reg_read(*ur))
&& info.used_registers().contains(®_w)
{
return true;
}
false
}
#[inline(always)]
pub fn has_ctrled_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 => continue,
iced_x86::OpKind::Memory => match instr.memory_base() {
iced_x86::Register::None => return false,
iced_x86::Register::RIP => return false,
iced_x86::Register::EIP => return false,
_ => continue,
},
_ => return false,
},
_ => return false,
}
}
op_cnt > 0
}