pyvex 9.2.193__cp310-cp310-macosx_10_12_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyvex/__init__.py +92 -0
- pyvex/_register_info.py +1800 -0
- pyvex/arches.py +94 -0
- pyvex/block.py +697 -0
- pyvex/const.py +426 -0
- pyvex/const_val.py +26 -0
- pyvex/data_ref.py +55 -0
- pyvex/enums.py +156 -0
- pyvex/errors.py +31 -0
- pyvex/expr.py +974 -0
- pyvex/include/libvex.h +1029 -0
- pyvex/include/libvex_basictypes.h +236 -0
- pyvex/include/libvex_emnote.h +142 -0
- pyvex/include/libvex_guest_amd64.h +252 -0
- pyvex/include/libvex_guest_arm.h +224 -0
- pyvex/include/libvex_guest_arm64.h +203 -0
- pyvex/include/libvex_guest_mips32.h +175 -0
- pyvex/include/libvex_guest_mips64.h +173 -0
- pyvex/include/libvex_guest_offsets.h +941 -0
- pyvex/include/libvex_guest_ppc32.h +298 -0
- pyvex/include/libvex_guest_ppc64.h +343 -0
- pyvex/include/libvex_guest_riscv64.h +148 -0
- pyvex/include/libvex_guest_s390x.h +201 -0
- pyvex/include/libvex_guest_tilegx.h +149 -0
- pyvex/include/libvex_guest_x86.h +322 -0
- pyvex/include/libvex_ir.h +3113 -0
- pyvex/include/libvex_s390x_common.h +123 -0
- pyvex/include/libvex_trc_values.h +99 -0
- pyvex/include/pyvex.h +96 -0
- pyvex/lib/libpyvex.dylib +0 -0
- pyvex/lifting/__init__.py +18 -0
- pyvex/lifting/gym/README.md +7 -0
- pyvex/lifting/gym/__init__.py +5 -0
- pyvex/lifting/gym/aarch64_spotter.py +40 -0
- pyvex/lifting/gym/arm_spotter.py +427 -0
- pyvex/lifting/gym/x86_spotter.py +129 -0
- pyvex/lifting/libvex.py +117 -0
- pyvex/lifting/lift_function.py +304 -0
- pyvex/lifting/lifter.py +124 -0
- pyvex/lifting/post_processor.py +16 -0
- pyvex/lifting/util/__init__.py +14 -0
- pyvex/lifting/util/instr_helper.py +422 -0
- pyvex/lifting/util/lifter_helper.py +154 -0
- pyvex/lifting/util/syntax_wrapper.py +312 -0
- pyvex/lifting/util/vex_helper.py +301 -0
- pyvex/lifting/zerodivision.py +71 -0
- pyvex/native.py +63 -0
- pyvex/py.typed +1 -0
- pyvex/stmt.py +740 -0
- pyvex/types.py +48 -0
- pyvex/utils.py +63 -0
- pyvex/vex_ffi.py +1453 -0
- pyvex-9.2.193.dist-info/METADATA +181 -0
- pyvex-9.2.193.dist-info/RECORD +59 -0
- pyvex-9.2.193.dist-info/WHEEL +6 -0
- pyvex-9.2.193.dist-info/licenses/LICENSE +24 -0
- pyvex-9.2.193.dist-info/licenses/pyvex_c/LICENSE +339 -0
- pyvex-9.2.193.dist-info/licenses/vex/LICENSE.GPL +340 -0
- pyvex-9.2.193.dist-info/licenses/vex/LICENSE.README +23 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import bitstring
|
|
4
|
+
|
|
5
|
+
from pyvex.lifting.util import JumpKind, Type
|
|
6
|
+
from pyvex.lifting.util.instr_helper import Instruction, ParseError
|
|
7
|
+
from pyvex.lifting.util.lifter_helper import GymratLifter
|
|
8
|
+
from pyvex.types import Arch
|
|
9
|
+
|
|
10
|
+
log = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ARMInstruction(Instruction): # pylint: disable=abstract-method
|
|
14
|
+
# NOTE: WARNING: There is no CPSR in VEX's ARM implementation
|
|
15
|
+
# You must use straight nasty hacks instead.
|
|
16
|
+
|
|
17
|
+
# NOTE 2: Something is goofy w/r/t archinfo and VEX; cc_op3 is used in ccalls, but there's
|
|
18
|
+
# no cc_op3 in archinfo, angr itself uses cc_depn instead. We do the same.
|
|
19
|
+
|
|
20
|
+
def match_instruction(self, data, bitstrm):
|
|
21
|
+
"""
|
|
22
|
+
ARM Instructions are pretty dense, so let's do what we can to weed them out
|
|
23
|
+
"""
|
|
24
|
+
if "c" not in data or data["c"] == "1111":
|
|
25
|
+
raise ParseError("Invalid ARM Instruction")
|
|
26
|
+
|
|
27
|
+
def get_N(self):
|
|
28
|
+
cc_op = self.get("cc_op", Type.int_32)
|
|
29
|
+
cc_dep1 = self.get("cc_dep1", Type.int_32)
|
|
30
|
+
cc_dep2 = self.get("cc_dep2", Type.int_32)
|
|
31
|
+
cc_depn = self.get("cc_ndep", Type.int_32)
|
|
32
|
+
return self.ccall(Type.int_32, "armg_calculate_flag_n", [cc_op, cc_dep1, cc_dep2, cc_depn])
|
|
33
|
+
|
|
34
|
+
def get_C(self):
|
|
35
|
+
cc_op = self.get("cc_op", Type.int_32)
|
|
36
|
+
cc_dep1 = self.get("cc_dep1", Type.int_32)
|
|
37
|
+
cc_dep2 = self.get("cc_dep2", Type.int_32)
|
|
38
|
+
cc_depn = self.get("cc_ndep", Type.int_32)
|
|
39
|
+
return self.ccall(Type.int_32, "armg_calculate_flag_c", [cc_op, cc_dep1, cc_dep2, cc_depn])
|
|
40
|
+
|
|
41
|
+
def get_V(self):
|
|
42
|
+
cc_op = self.get("cc_op", Type.int_32)
|
|
43
|
+
cc_dep1 = self.get("cc_dep1", Type.int_32)
|
|
44
|
+
cc_dep2 = self.get("cc_dep2", Type.int_32)
|
|
45
|
+
cc_depn = self.get("cc_ndep", Type.int_32)
|
|
46
|
+
return self.ccall(Type.int_32, "armg_calculate_flag_v", [cc_op, cc_dep1, cc_dep2, cc_depn])
|
|
47
|
+
|
|
48
|
+
def get_Z(self):
|
|
49
|
+
cc_op = self.get("cc_op", Type.int_32)
|
|
50
|
+
cc_dep1 = self.get("cc_dep1", Type.int_32)
|
|
51
|
+
cc_dep2 = self.get("cc_dep2", Type.int_32)
|
|
52
|
+
cc_depn = self.get("cc_ndep", Type.int_32)
|
|
53
|
+
return self.ccall(Type.int_32, "armg_calculate_flag_z", [cc_op.rdt, cc_dep1.rdt, cc_dep2.rdt, cc_depn.rdt])
|
|
54
|
+
|
|
55
|
+
def evaluate_condition(self):
|
|
56
|
+
# condition codes should be in 'c'
|
|
57
|
+
cond = self.data["c"]
|
|
58
|
+
if cond == "0000":
|
|
59
|
+
# equal, z set
|
|
60
|
+
return self.get_Z() == 1
|
|
61
|
+
elif cond == "0001":
|
|
62
|
+
# not equal, Z clear
|
|
63
|
+
return self.get_Z() == 0
|
|
64
|
+
elif cond == "0010":
|
|
65
|
+
# Carry, C set
|
|
66
|
+
return self.get_C() == 1
|
|
67
|
+
elif cond == "0011":
|
|
68
|
+
# Carry Clear, C clear
|
|
69
|
+
return self.get_C() == 0
|
|
70
|
+
elif cond == "0100":
|
|
71
|
+
# MI / neagative / N set
|
|
72
|
+
return self.get_N() == 1
|
|
73
|
+
elif cond == "0101":
|
|
74
|
+
# PL / plus / positive / N clear
|
|
75
|
+
return self.get_N() == 0
|
|
76
|
+
elif cond == "0110":
|
|
77
|
+
# VS / V set / Overflow
|
|
78
|
+
return self.get_V() == 1
|
|
79
|
+
elif cond == "0111":
|
|
80
|
+
# VC / V Clear / no overflow
|
|
81
|
+
return self.get_V() == 0
|
|
82
|
+
elif cond == "1000":
|
|
83
|
+
# Hi / unsigned higher / C set, Z clear
|
|
84
|
+
return (self.get_C() == 1) & (self.get_Z() == 0)
|
|
85
|
+
elif cond == "1001":
|
|
86
|
+
# LS / C clear, Z set
|
|
87
|
+
return (self.get_C() == 0) & (self.get_Z() == 1)
|
|
88
|
+
elif cond == "1011":
|
|
89
|
+
# LT / Less than / N != V
|
|
90
|
+
return self.get_N() != self.get_V()
|
|
91
|
+
elif cond == "1100":
|
|
92
|
+
# GT / greater than / Z clear and (n == v)
|
|
93
|
+
return (self.get_Z() == 1) & (self.get_N() != self.get_V())
|
|
94
|
+
elif cond == "1101":
|
|
95
|
+
# LE / less than or equal to / Z set OR (N != V)
|
|
96
|
+
return (self.get_Z() == 1) | (self.get_N() != self.get_V())
|
|
97
|
+
else:
|
|
98
|
+
# No condition
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
def _load_le_instr(self, bitstream: bitstring.ConstBitStream, numbits: int) -> str:
|
|
102
|
+
# THUMB mode instructions swap endianness every two bytes!
|
|
103
|
+
if (self.addr & 1) == 1 and numbits > 16:
|
|
104
|
+
chunk = ""
|
|
105
|
+
oldpos = bitstream.pos
|
|
106
|
+
try:
|
|
107
|
+
for _ in range(0, numbits, 16):
|
|
108
|
+
chunk += bitstring.Bits(uint=bitstream.peek("uintle:%d" % 16), length=16).bin
|
|
109
|
+
bitstream.pos += 16
|
|
110
|
+
finally:
|
|
111
|
+
bitstream.pos = oldpos
|
|
112
|
+
return chunk
|
|
113
|
+
return super()._load_le_instr(bitstream, numbits)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class Instruction_MRC(ARMInstruction):
|
|
117
|
+
name = "MRC"
|
|
118
|
+
bin_format = "cccc1110CCC1nnnnddddppppOOOOOOOO"
|
|
119
|
+
# 11101110000100010001111100010000
|
|
120
|
+
# c = cond
|
|
121
|
+
# C = Coprocessor operation mode
|
|
122
|
+
# d = CPd
|
|
123
|
+
# O = Offset
|
|
124
|
+
# p = CP#
|
|
125
|
+
|
|
126
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
127
|
+
# TODO at least look at the conditionals
|
|
128
|
+
# TODO Clobber the dst reg of MCR
|
|
129
|
+
# TODO maybe treat coproc regs as simple storage (even though they are very much not)
|
|
130
|
+
log.debug("Ignoring MRC instruction at %#x.", self.addr)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class Instruction_MCR(ARMInstruction):
|
|
134
|
+
name = "MCR"
|
|
135
|
+
bin_format = "cccc1110CCC0nnnnddddppppOOOOOOOO"
|
|
136
|
+
# 11101110000000010000111100010000
|
|
137
|
+
# c = cond
|
|
138
|
+
# C = Coprocessor operation mode
|
|
139
|
+
# d = CPd
|
|
140
|
+
# O = Offset
|
|
141
|
+
# p = CP#
|
|
142
|
+
|
|
143
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
144
|
+
# TODO at least look at the conditionals
|
|
145
|
+
# TODO Clobber the dst reg of MCR
|
|
146
|
+
# TODO maybe treat coproc regs as simple storage (even though they are very much not)
|
|
147
|
+
log.debug("Ignoring MCR instruction at %#x.", self.addr)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class Instruction_MSR(ARMInstruction):
|
|
151
|
+
name = "MSR"
|
|
152
|
+
bin_format = "cccc00i10d10xxxj1111ssssssssssss"
|
|
153
|
+
# 11100011001000011111000010010001
|
|
154
|
+
# 11100001011011111111000000000001
|
|
155
|
+
|
|
156
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
157
|
+
log.debug(
|
|
158
|
+
"Ignoring MSR instruction at %#x. VEX cannot support this instruction. "
|
|
159
|
+
"See pyvex/lifting/gym/arm_spotter.py",
|
|
160
|
+
self.addr,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class Instruction_MRS(ARMInstruction):
|
|
165
|
+
name = "MRS"
|
|
166
|
+
bin_format = "cccc00010s001111dddd000000000000"
|
|
167
|
+
|
|
168
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
169
|
+
log.debug(
|
|
170
|
+
"Ignoring MRS instruction at %#x. VEX cannot support this instruction. "
|
|
171
|
+
"See pyvex/lifting/gym/arm_spotter.py",
|
|
172
|
+
self.addr,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class Instruction_STM(ARMInstruction):
|
|
177
|
+
name = "STM"
|
|
178
|
+
bin_format = "cccc100pu1w0bbbbrrrrrrrrrrrrrrrr"
|
|
179
|
+
|
|
180
|
+
def match_instruction(self, data, bitstrm):
|
|
181
|
+
# If we don't push anything, that's not real
|
|
182
|
+
if int(data["r"]) == 0:
|
|
183
|
+
raise ParseError("Invalid STM instruction")
|
|
184
|
+
return True
|
|
185
|
+
|
|
186
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
187
|
+
log.debug(
|
|
188
|
+
"Ignoring STMxx ^ instruction at %#x. This mode is not implemented by VEX! "
|
|
189
|
+
"See pyvex/lifting/gym/arm_spotter.py",
|
|
190
|
+
self.addr,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class Instruction_LDM(ARMInstruction):
|
|
195
|
+
name = "LDM"
|
|
196
|
+
bin_format = "cccc100PU1W1bbbbrrrrrrrrrrrrrrrr"
|
|
197
|
+
|
|
198
|
+
def match_instruction(self, data, bitstrm):
|
|
199
|
+
# If we don't push anything, that's not real
|
|
200
|
+
if int(data["r"]) == 0:
|
|
201
|
+
raise ParseError("Invalid LDM instruction")
|
|
202
|
+
return True
|
|
203
|
+
|
|
204
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
205
|
+
# test if PC will be set. If so, the jumpkind of this block should be Ijk_Ret
|
|
206
|
+
log.debug("Spotting an LDM instruction at %#x. This is not fully tested. Prepare for errors.", self.addr)
|
|
207
|
+
|
|
208
|
+
src_n = f"r{int(self.data['b'], 2)}"
|
|
209
|
+
src = self.get(src_n, Type.int_32)
|
|
210
|
+
|
|
211
|
+
for reg_num, bit in enumerate(self.data["r"]):
|
|
212
|
+
reg_num = 15 - reg_num
|
|
213
|
+
if bit == "1":
|
|
214
|
+
if self.data["P"] == "1":
|
|
215
|
+
if self.data["U"] == "0":
|
|
216
|
+
src += 4
|
|
217
|
+
else:
|
|
218
|
+
src -= 4
|
|
219
|
+
val = self.load(src, Type.int_32)
|
|
220
|
+
self.put(val, f"r{reg_num}")
|
|
221
|
+
if self.data["P"] == "0":
|
|
222
|
+
if self.data["U"] == "0":
|
|
223
|
+
src += 4
|
|
224
|
+
else:
|
|
225
|
+
src -= 4
|
|
226
|
+
# If we touch PC, we're doing a RET!
|
|
227
|
+
if reg_num == 15 and bit == "1":
|
|
228
|
+
cond = self.evaluate_condition()
|
|
229
|
+
if cond is not None:
|
|
230
|
+
self.jump(cond, val, JumpKind.Ret)
|
|
231
|
+
else:
|
|
232
|
+
self.jump(None, val, JumpKind.Ret)
|
|
233
|
+
# Write-back
|
|
234
|
+
if self.data["W"] == "1":
|
|
235
|
+
self.put(src, src_n)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class Instruction_STC(ARMInstruction):
|
|
239
|
+
name = "STC"
|
|
240
|
+
bin_format = "cccc110PUNW0nnnnddddppppOOOOOOOO"
|
|
241
|
+
|
|
242
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
243
|
+
# TODO At least look at the conditionals
|
|
244
|
+
log.debug("Ignoring STC instruction at %#x.", self.addr)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class Instruction_STC_THUMB(ARMInstruction):
|
|
248
|
+
name = "STC"
|
|
249
|
+
bin_format = "111c110PUNW0nnnnddddppppOOOOOOOO"
|
|
250
|
+
|
|
251
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
252
|
+
# TODO At least look at the conditionals
|
|
253
|
+
log.debug("Ignoring STC instruction at %#x.", self.addr)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class Instruction_LDC(ARMInstruction):
|
|
257
|
+
name = "LDC"
|
|
258
|
+
bin_format = "cccc110PUNW1nnnnddddppppOOOOOOOO"
|
|
259
|
+
|
|
260
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
261
|
+
# TODO At least look at the conditionals
|
|
262
|
+
# TODO Clobber the dest reg of LDC
|
|
263
|
+
# TODO Maybe clobber the dst reg of CDP, if we're really adventurous
|
|
264
|
+
log.debug("Ignoring LDC instruction at %#x.", self.addr)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class Instruction_LDC_THUMB(ARMInstruction):
|
|
268
|
+
name = "LDC"
|
|
269
|
+
bin_format = "111c110PUNW1nnnnddddppppOOOOOOOO"
|
|
270
|
+
|
|
271
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
272
|
+
# TODO At least look at the conditionals
|
|
273
|
+
# TODO Clobber the dest reg of LDC
|
|
274
|
+
# TODO Maybe clobber the dst reg of CDP, if we're really adventurous
|
|
275
|
+
log.debug("Ignoring LDC instruction at %#x.", self.addr)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class Instruction_CDP(Instruction):
|
|
279
|
+
name = "CDP"
|
|
280
|
+
bin_format = "cccc1110oooonnnnddddppppPPP0mmmm"
|
|
281
|
+
# c = cond
|
|
282
|
+
# d = CPd
|
|
283
|
+
# O = Offset
|
|
284
|
+
# p = CP#
|
|
285
|
+
|
|
286
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
287
|
+
# TODO At least look at the conditionals
|
|
288
|
+
# TODO Maybe clobber the dst reg of CDP, if we're really adventurous
|
|
289
|
+
log.debug("Ignoring CDP instruction at %#x.", self.addr)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
##
|
|
293
|
+
## Thumb! (ugh)
|
|
294
|
+
##
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
class ThumbInstruction(Instruction): # pylint: disable=abstract-method
|
|
298
|
+
def mark_instruction_start(self):
|
|
299
|
+
self.irsb_c.imark(self.addr - 1, self.bytewidth, 1)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
class Instruction_tCPSID(ThumbInstruction):
|
|
303
|
+
name = "CPSID"
|
|
304
|
+
bin_format = "101101x0011x0010"
|
|
305
|
+
|
|
306
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
307
|
+
# TODO haha lol yeah right
|
|
308
|
+
log.debug("[thumb] Ignoring CPS instruction at %#x.", self.addr)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class Instruction_tMSR(ThumbInstruction):
|
|
312
|
+
name = "tMSR"
|
|
313
|
+
bin_format = "10x0mmmmxxxxxxxx11110011100Rrrrr"
|
|
314
|
+
|
|
315
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
316
|
+
dest_spec_reg = int(self.data["x"], 2)
|
|
317
|
+
src_reg = f"r{int(self.data['r'], 2)}"
|
|
318
|
+
|
|
319
|
+
# If 0, do not write the SPSR
|
|
320
|
+
if self.data["R"] == "0":
|
|
321
|
+
if dest_spec_reg == 8: # msp
|
|
322
|
+
src = self.get(src_reg, Type.int_32)
|
|
323
|
+
self.put(src, "sp")
|
|
324
|
+
elif dest_spec_reg == 16: # primask
|
|
325
|
+
src = self.get(src_reg, Type.int_32)
|
|
326
|
+
self.put(src, "primask")
|
|
327
|
+
else:
|
|
328
|
+
log.debug(
|
|
329
|
+
"[thumb] FIXME: tMSR at %#x is writing into an unsupported special register %#x. "
|
|
330
|
+
"Ignoring the instruction.",
|
|
331
|
+
self.addr,
|
|
332
|
+
dest_spec_reg,
|
|
333
|
+
)
|
|
334
|
+
else:
|
|
335
|
+
log.debug("[thumb] tMSR at %#x is writing SPSR. Ignoring the instruction. FixMe.", self.addr)
|
|
336
|
+
log.debug(
|
|
337
|
+
"[thumb] Spotting an tMSR instruction at %#x. This is not fully tested. Prepare for errors.", self.addr
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
class Instruction_tMRS(ThumbInstruction):
|
|
342
|
+
name = "tMRS"
|
|
343
|
+
bin_format = "10x0mmmmxxxxxxxx11110011111Rrrrr"
|
|
344
|
+
|
|
345
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
346
|
+
spec_reg = int(self.data["x"], 2)
|
|
347
|
+
dest_reg = f"r{int(self.data['m'], 2)}"
|
|
348
|
+
|
|
349
|
+
# Reading from CPSR
|
|
350
|
+
if self.data["R"] == "0":
|
|
351
|
+
# See special registers constants here:
|
|
352
|
+
# https://github.com/aquynh/capstone/blob/45bec1a691e455b864f7e4d394711a467e5493dc/arch/ARM/ARMInstPrinter.c#L1654
|
|
353
|
+
if spec_reg == 8:
|
|
354
|
+
# We move the SP and call it a day.
|
|
355
|
+
src = self.get("sp", Type.int_32)
|
|
356
|
+
self.put(src, dest_reg)
|
|
357
|
+
elif spec_reg == 16:
|
|
358
|
+
src = self.get("primask", Type.int_32)
|
|
359
|
+
self.put(src, dest_reg)
|
|
360
|
+
else:
|
|
361
|
+
log.debug(
|
|
362
|
+
"[thumb] FIXME: tMRS at %#x is using the unsupported special register %#x. "
|
|
363
|
+
"Ignoring the instruction.",
|
|
364
|
+
self.addr,
|
|
365
|
+
spec_reg,
|
|
366
|
+
)
|
|
367
|
+
else:
|
|
368
|
+
log.debug("[thumb] tMRS at %#x is reading from SPSR. Ignoring the instruction. FixMe.", self.addr)
|
|
369
|
+
log.debug("[thumb] Ignoring tMRS instruction at %#x.", self.addr)
|
|
370
|
+
log.debug(
|
|
371
|
+
"[thumb] Spotting an tMRS instruction at %#x. This is not fully tested. Prepare for errors.", self.addr
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class Instruction_tDMB(ThumbInstruction):
|
|
376
|
+
name = "DMB"
|
|
377
|
+
bin_format = "100011110101xxxx1111001110111111"
|
|
378
|
+
|
|
379
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
380
|
+
# TODO haha lol yeah right
|
|
381
|
+
log.debug("[thumb] Ignoring DMB instruction at %#x.", self.addr)
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
class Instruction_WFI(ThumbInstruction):
|
|
385
|
+
name = "WFI"
|
|
386
|
+
bin_format = "10111111001a0000"
|
|
387
|
+
# 1011111100110000
|
|
388
|
+
|
|
389
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
390
|
+
log.debug("[thumb] Ignoring WFI instruction at %#x.", self.addr)
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
class ARMSpotter(GymratLifter):
|
|
394
|
+
arm_instrs = [
|
|
395
|
+
Instruction_MRC,
|
|
396
|
+
Instruction_MCR,
|
|
397
|
+
Instruction_MSR,
|
|
398
|
+
Instruction_MRS,
|
|
399
|
+
Instruction_STM,
|
|
400
|
+
Instruction_LDM,
|
|
401
|
+
Instruction_STC,
|
|
402
|
+
Instruction_LDC,
|
|
403
|
+
Instruction_CDP,
|
|
404
|
+
]
|
|
405
|
+
thumb_instrs = [
|
|
406
|
+
Instruction_tCPSID,
|
|
407
|
+
Instruction_tMSR,
|
|
408
|
+
Instruction_tMRS,
|
|
409
|
+
Instruction_WFI,
|
|
410
|
+
Instruction_tDMB,
|
|
411
|
+
Instruction_STC_THUMB,
|
|
412
|
+
Instruction_LDC_THUMB,
|
|
413
|
+
]
|
|
414
|
+
|
|
415
|
+
def __init__(self, arch: Arch, addr: int):
|
|
416
|
+
super().__init__(arch, addr)
|
|
417
|
+
self.thumb: bool = False
|
|
418
|
+
|
|
419
|
+
def _lift(self):
|
|
420
|
+
if self.irsb.addr & 1:
|
|
421
|
+
# Thumb!
|
|
422
|
+
self.instrs = self.thumb_instrs
|
|
423
|
+
self.thumb = True
|
|
424
|
+
else:
|
|
425
|
+
self.instrs = self.arm_instrs
|
|
426
|
+
self.thumb = False
|
|
427
|
+
super()._lift()
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from pyvex.lifting.util import GymratLifter, Instruction, JumpKind, Type
|
|
4
|
+
|
|
5
|
+
log = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
# pylint: disable=missing-class-docstring
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Instruction_SWAPGS(Instruction):
|
|
11
|
+
name = "SWAPGS"
|
|
12
|
+
bin_format = "000011110000000111111000" # 0f 01 f8
|
|
13
|
+
|
|
14
|
+
def compute_result(self, *args):
|
|
15
|
+
pass # TODO check for priv mode
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Instruction_SYSRET(Instruction):
|
|
19
|
+
name = "SYSRET"
|
|
20
|
+
bin_format = "010010000000111100000111" # 48 04 07
|
|
21
|
+
|
|
22
|
+
def compute_result(self, *args):
|
|
23
|
+
result = self.dirty(Type.int_64, "%sg_dirtyhelper_SYSRET" % self.arch.name.lower(), ())
|
|
24
|
+
self.jump(None, result, JumpKind.Ret)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Instruction_IRETQ(Instruction):
|
|
28
|
+
name = "IRETQ"
|
|
29
|
+
bin_format = "0100100011001111" # 48 cf
|
|
30
|
+
|
|
31
|
+
def compute_result(self, *args):
|
|
32
|
+
result = self.dirty(Type.int_64, "%sg_dirtyhelper_IRETQ" % self.arch.name.lower(), ())
|
|
33
|
+
self.jump(None, result, JumpKind.Ret)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Instruction_RDMSR(Instruction):
|
|
37
|
+
name = "RDMSR"
|
|
38
|
+
bin_format = "0000111100110010" # 0f 32
|
|
39
|
+
|
|
40
|
+
def compute_result(self, *args):
|
|
41
|
+
ecx = self.get("ecx", Type.int_32)
|
|
42
|
+
result = self.dirty(Type.int_64, "%sg_dirtyhelper_RDMSR" % self.arch.name.lower(), (ecx,))
|
|
43
|
+
edx = result.narrow_high(Type.int_32)
|
|
44
|
+
eax = result.narrow_low(Type.int_32)
|
|
45
|
+
if self.arch.bits == 32:
|
|
46
|
+
self.put(eax, "eax")
|
|
47
|
+
self.put(edx, "edx")
|
|
48
|
+
else:
|
|
49
|
+
self.put(eax.widen_unsigned(Type.int_64), "rax")
|
|
50
|
+
self.put(edx.widen_unsigned(Type.int_64), "rdx")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Instruction_XGETBV(Instruction):
|
|
54
|
+
name = "XGETBV"
|
|
55
|
+
bin_format = "000011110000000111010000" # 0f 01 d0
|
|
56
|
+
|
|
57
|
+
def compute_result(self, *args):
|
|
58
|
+
ecx = self.get("ecx", Type.int_32)
|
|
59
|
+
result = self.dirty(Type.int_64, "%sg_dirtyhelper_XGETBV" % self.arch.name.lower(), (ecx,))
|
|
60
|
+
edx = result.narrow_high(Type.int_32)
|
|
61
|
+
eax = result.narrow_low(Type.int_32)
|
|
62
|
+
if self.arch.bits == 32:
|
|
63
|
+
self.put(eax, "eax")
|
|
64
|
+
self.put(edx, "edx")
|
|
65
|
+
else:
|
|
66
|
+
self.put(eax.widen_unsigned(Type.int_64), "rax")
|
|
67
|
+
self.put(edx.widen_unsigned(Type.int_64), "rdx")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class Instruction_AAM(Instruction):
|
|
71
|
+
name = "AAM"
|
|
72
|
+
bin_format = "11010100iiiiiiii"
|
|
73
|
+
|
|
74
|
+
# From https://www.felixcloutier.com/x86/aam
|
|
75
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
76
|
+
base = self.constant(int(self.data["i"], 2), Type.int_8)
|
|
77
|
+
temp_al = self.get("al", Type.int_8)
|
|
78
|
+
temp_ah = temp_al // base
|
|
79
|
+
temp_al = temp_al % base
|
|
80
|
+
self.put(temp_ah, "ah")
|
|
81
|
+
self.put(temp_al, "al")
|
|
82
|
+
log.debug(
|
|
83
|
+
"The generalized AAM instruction is not supported by VEX, and is handled specially by pyvex."
|
|
84
|
+
" It has no flag handling at present. See pyvex/lifting/gym/x86_spotter.py for details"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# TODO: Flags
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class Instruction_AAD(Instruction):
|
|
91
|
+
name = "AAD"
|
|
92
|
+
bin_format = "11010101iiiiiiii"
|
|
93
|
+
|
|
94
|
+
# From https://www.felixcloutier.com/x86/aad
|
|
95
|
+
def compute_result(self): # pylint: disable=arguments-differ
|
|
96
|
+
base = self.constant(int(self.data["i"], 2), Type.int_8)
|
|
97
|
+
temp_al = self.get("al", Type.int_8)
|
|
98
|
+
temp_ah = self.get("ah", Type.int_8)
|
|
99
|
+
temp_al = (temp_al + (temp_ah * base)) & 0xFF
|
|
100
|
+
temp_ah = self.constant(0, Type.int_8)
|
|
101
|
+
self.put(temp_ah, "ah")
|
|
102
|
+
self.put(temp_al, "al")
|
|
103
|
+
log.debug(
|
|
104
|
+
"The generalized AAD instruction is not supported by VEX, and is handled specially by pyvex."
|
|
105
|
+
" It has no flag handling at present. See pyvex/lifting/gym/x86_spotter.py for details"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# TODO: Flags
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class AMD64Spotter(GymratLifter):
|
|
112
|
+
instrs = [
|
|
113
|
+
Instruction_RDMSR,
|
|
114
|
+
Instruction_XGETBV,
|
|
115
|
+
Instruction_AAD,
|
|
116
|
+
Instruction_AAM,
|
|
117
|
+
Instruction_SWAPGS,
|
|
118
|
+
Instruction_IRETQ,
|
|
119
|
+
Instruction_SYSRET,
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class X86Spotter(GymratLifter):
|
|
124
|
+
instrs = [
|
|
125
|
+
Instruction_RDMSR,
|
|
126
|
+
Instruction_XGETBV,
|
|
127
|
+
Instruction_AAD,
|
|
128
|
+
Instruction_AAM,
|
|
129
|
+
]
|
pyvex/lifting/libvex.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import threading
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from pyvex.errors import LiftingException
|
|
6
|
+
from pyvex.native import ffi, pvc
|
|
7
|
+
from pyvex.types import CLiftSource, LibvexArch
|
|
8
|
+
|
|
9
|
+
from .lift_function import Lifter
|
|
10
|
+
|
|
11
|
+
log = logging.getLogger("pyvex.lifting.libvex")
|
|
12
|
+
|
|
13
|
+
_libvex_lock = threading.Lock()
|
|
14
|
+
|
|
15
|
+
LIBVEX_SUPPORTED_ARCHES = {
|
|
16
|
+
"X86",
|
|
17
|
+
"AMD64",
|
|
18
|
+
"MIPS32",
|
|
19
|
+
"MIPS64",
|
|
20
|
+
"ARM",
|
|
21
|
+
"ARMEL",
|
|
22
|
+
"ARMHF",
|
|
23
|
+
"ARMCortexM",
|
|
24
|
+
"AARCH64",
|
|
25
|
+
"PPC32",
|
|
26
|
+
"PPC64",
|
|
27
|
+
"S390X",
|
|
28
|
+
"RISCV64",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
VEX_MAX_INSTRUCTIONS = 99
|
|
32
|
+
VEX_MAX_BYTES = 5000
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class VexRegisterUpdates:
|
|
36
|
+
VexRegUpd_INVALID = 0x700
|
|
37
|
+
VexRegUpdSpAtMemAccess = 0x701
|
|
38
|
+
VexRegUpdUnwindregsAtMemAccess = 0x702
|
|
39
|
+
VexRegUpdAllregsAtMemAccess = 0x703
|
|
40
|
+
VexRegUpdAllregsAtEachInsn = 0x704
|
|
41
|
+
VexRegUpdLdAllregsAtEachInsn = 0x705
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class LibVEXLifter(Lifter):
|
|
45
|
+
__slots__ = ()
|
|
46
|
+
|
|
47
|
+
REQUIRE_DATA_C = True
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def get_vex_log():
|
|
51
|
+
return bytes(ffi.buffer(pvc.msg_buffer, pvc.msg_current_size)).decode() if pvc.msg_buffer != ffi.NULL else None
|
|
52
|
+
|
|
53
|
+
def _lift(self):
|
|
54
|
+
if TYPE_CHECKING:
|
|
55
|
+
assert isinstance(self.irsb.arch, LibvexArch)
|
|
56
|
+
assert isinstance(self.data, CLiftSource)
|
|
57
|
+
try:
|
|
58
|
+
_libvex_lock.acquire()
|
|
59
|
+
|
|
60
|
+
pvc.log_level = log.getEffectiveLevel()
|
|
61
|
+
vex_arch = getattr(pvc, self.irsb.arch.vex_arch, None)
|
|
62
|
+
assert vex_arch is not None
|
|
63
|
+
|
|
64
|
+
if self.bytes_offset is None:
|
|
65
|
+
self.bytes_offset = 0
|
|
66
|
+
|
|
67
|
+
if self.max_bytes is None or self.max_bytes > VEX_MAX_BYTES:
|
|
68
|
+
max_bytes = VEX_MAX_BYTES
|
|
69
|
+
else:
|
|
70
|
+
max_bytes = self.max_bytes
|
|
71
|
+
|
|
72
|
+
if self.max_inst is None or self.max_inst > VEX_MAX_INSTRUCTIONS:
|
|
73
|
+
max_inst = VEX_MAX_INSTRUCTIONS
|
|
74
|
+
else:
|
|
75
|
+
max_inst = self.max_inst
|
|
76
|
+
|
|
77
|
+
strict_block_end = self.strict_block_end
|
|
78
|
+
if strict_block_end is None:
|
|
79
|
+
strict_block_end = True
|
|
80
|
+
|
|
81
|
+
if self.cross_insn_opt:
|
|
82
|
+
px_control = VexRegisterUpdates.VexRegUpdUnwindregsAtMemAccess
|
|
83
|
+
else:
|
|
84
|
+
px_control = VexRegisterUpdates.VexRegUpdLdAllregsAtEachInsn
|
|
85
|
+
|
|
86
|
+
self.irsb.arch.vex_archinfo["hwcache_info"]["caches"] = ffi.NULL
|
|
87
|
+
lift_r = pvc.vex_lift(
|
|
88
|
+
vex_arch,
|
|
89
|
+
self.irsb.arch.vex_archinfo,
|
|
90
|
+
self.data + self.bytes_offset,
|
|
91
|
+
self.irsb.addr,
|
|
92
|
+
max_inst,
|
|
93
|
+
max_bytes,
|
|
94
|
+
self.opt_level,
|
|
95
|
+
self.traceflags,
|
|
96
|
+
self.allow_arch_optimizations,
|
|
97
|
+
strict_block_end,
|
|
98
|
+
1 if self.collect_data_refs else 0,
|
|
99
|
+
1 if self.load_from_ro_regions else 0,
|
|
100
|
+
1 if self.const_prop else 0,
|
|
101
|
+
px_control,
|
|
102
|
+
self.bytes_offset,
|
|
103
|
+
)
|
|
104
|
+
log_str = self.get_vex_log()
|
|
105
|
+
if lift_r == ffi.NULL:
|
|
106
|
+
raise LiftingException("libvex: unknown error" if log_str is None else log_str)
|
|
107
|
+
else:
|
|
108
|
+
if log_str is not None:
|
|
109
|
+
log.debug(log_str)
|
|
110
|
+
|
|
111
|
+
self.irsb._from_c(lift_r, skip_stmts=self.skip_stmts)
|
|
112
|
+
if self.irsb.size == 0:
|
|
113
|
+
log.debug("raising lifting exception")
|
|
114
|
+
raise LiftingException("libvex: could not decode any instructions @ 0x%x" % self.addr)
|
|
115
|
+
finally:
|
|
116
|
+
_libvex_lock.release()
|
|
117
|
+
self.irsb.arch.vex_archinfo["hwcache_info"]["caches"] = None
|