angr 9.2.145__py3-none-manylinux2014_x86_64.whl → 9.2.147__py3-none-manylinux2014_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.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/bindiff.py +343 -68
- angr/analyses/cfg/cfg_arch_options.py +10 -0
- angr/analyses/cfg/cfg_base.py +39 -15
- angr/analyses/cfg/cfg_fast.py +19 -3
- angr/analyses/decompiler/optimization_passes/engine_base.py +9 -1
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +11 -0
- angr/analyses/decompiler/ssailification/ssailification.py +1 -1
- angr/analyses/flirt/__init__.py +47 -0
- angr/analyses/flirt/consts.py +160 -0
- angr/analyses/{flirt.py → flirt/flirt.py} +99 -38
- angr/analyses/flirt/flirt_function.py +20 -0
- angr/analyses/flirt/flirt_matcher.py +351 -0
- angr/analyses/flirt/flirt_module.py +32 -0
- angr/analyses/flirt/flirt_node.py +23 -0
- angr/analyses/flirt/flirt_sig.py +356 -0
- angr/analyses/flirt/flirt_utils.py +31 -0
- angr/analyses/stack_pointer_tracker.py +34 -0
- angr/analyses/typehoon/lifter.py +11 -1
- angr/analyses/typehoon/simple_solver.py +9 -0
- angr/analyses/typehoon/translator.py +16 -0
- angr/analyses/typehoon/typeconsts.py +8 -8
- angr/analyses/vfg.py +1 -1
- angr/block.py +6 -6
- angr/engines/vex/heavy/concretizers.py +10 -0
- angr/flirt/__init__.py +15 -44
- angr/knowledge_plugins/functions/function.py +4 -4
- {angr-9.2.145.dist-info → angr-9.2.147.dist-info}/METADATA +6 -7
- {angr-9.2.145.dist-info → angr-9.2.147.dist-info}/RECORD +33 -25
- {angr-9.2.145.dist-info → angr-9.2.147.dist-info}/WHEEL +1 -1
- {angr-9.2.145.dist-info → angr-9.2.147.dist-info}/LICENSE +0 -0
- {angr-9.2.145.dist-info → angr-9.2.147.dist-info}/entry_points.txt +0 -0
- {angr-9.2.145.dist-info → angr-9.2.147.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import struct
|
|
3
|
+
import zlib
|
|
4
|
+
from io import BytesIO
|
|
5
|
+
|
|
6
|
+
from angr.errors import AngrError
|
|
7
|
+
from .consts import FlirtParseFlag, FlirtFeatureFlag, FlirtFunctionFlag
|
|
8
|
+
from .flirt_utils import read_max_2_bytes, read_multiple_bytes
|
|
9
|
+
from .flirt_function import FlirtFunction
|
|
10
|
+
from .flirt_module import FlirtModule
|
|
11
|
+
from .flirt_node import FlirtNode
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FlirtSignatureError(AngrError):
|
|
15
|
+
"""
|
|
16
|
+
Describes errors related to FLIRT signatures, especially parsing.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FlirtSignature:
|
|
21
|
+
"""
|
|
22
|
+
This class describes a FLIRT signature without any internal data that is only available after parsing.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
arch: str,
|
|
28
|
+
platform: str,
|
|
29
|
+
sig_name: str,
|
|
30
|
+
sig_path: str,
|
|
31
|
+
unique_strings: set[str] | None = None,
|
|
32
|
+
compiler: str | None = None,
|
|
33
|
+
compiler_version: str | None = None,
|
|
34
|
+
os_name: str | None = None,
|
|
35
|
+
os_version: str | None = None,
|
|
36
|
+
):
|
|
37
|
+
self.arch = arch
|
|
38
|
+
self.platform = platform
|
|
39
|
+
self.sig_name = sig_name
|
|
40
|
+
self.sig_path = sig_path
|
|
41
|
+
self.unique_strings = unique_strings
|
|
42
|
+
self.compiler = compiler
|
|
43
|
+
self.compiler_version = compiler_version
|
|
44
|
+
self.os_name = os_name
|
|
45
|
+
self.os_version = os_version
|
|
46
|
+
|
|
47
|
+
def __repr__(self):
|
|
48
|
+
if self.os_name:
|
|
49
|
+
if self.os_version:
|
|
50
|
+
return f"<{self.sig_name}@{self.arch}-{self.os_name}-{self.os_version}>"
|
|
51
|
+
return f"<{self.sig_name}@{self.arch}-{self.os_name}>"
|
|
52
|
+
return f"<{self.sig_name}@{self.arch}-{self.platform}>"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class FlirtSignatureParsed:
|
|
56
|
+
"""
|
|
57
|
+
Describes a FLIRT signature file after parsing.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
__slots__ = (
|
|
61
|
+
"app_types",
|
|
62
|
+
"arch",
|
|
63
|
+
"crc",
|
|
64
|
+
"ctype",
|
|
65
|
+
"ctypes_crc",
|
|
66
|
+
"features",
|
|
67
|
+
"file_types",
|
|
68
|
+
"libname",
|
|
69
|
+
"nfuncs",
|
|
70
|
+
"os_types",
|
|
71
|
+
"pattern_size",
|
|
72
|
+
"root",
|
|
73
|
+
"version",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def __init__(
|
|
77
|
+
self,
|
|
78
|
+
version: int,
|
|
79
|
+
arch: int,
|
|
80
|
+
file_types: int,
|
|
81
|
+
os_types: int,
|
|
82
|
+
app_types: int,
|
|
83
|
+
features: int,
|
|
84
|
+
crc: int,
|
|
85
|
+
ctype: int,
|
|
86
|
+
ctypes_crc: int,
|
|
87
|
+
nfuncs: int | None,
|
|
88
|
+
pattern_size: int | None,
|
|
89
|
+
libname: str,
|
|
90
|
+
root: FlirtNode | None,
|
|
91
|
+
):
|
|
92
|
+
self.version = version
|
|
93
|
+
self.arch = arch
|
|
94
|
+
self.file_types = file_types
|
|
95
|
+
self.os_types = os_types
|
|
96
|
+
self.app_types = app_types
|
|
97
|
+
self.features = features
|
|
98
|
+
self.crc = crc
|
|
99
|
+
self.ctype = ctype
|
|
100
|
+
self.ctypes_crc = ctypes_crc
|
|
101
|
+
self.nfuncs = nfuncs
|
|
102
|
+
self.pattern_size = pattern_size
|
|
103
|
+
self.libname = libname
|
|
104
|
+
self.root = root
|
|
105
|
+
|
|
106
|
+
def parse_tree(self, file_obj, root: bool = False) -> FlirtNode:
|
|
107
|
+
"""
|
|
108
|
+
Parse a FLIRT function tree.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
if not root:
|
|
112
|
+
length = file_obj.read(1)[0]
|
|
113
|
+
variant_mask = self.parse_variant_mask(file_obj, length)
|
|
114
|
+
pattern = self.parse_node(file_obj, length, variant_mask)
|
|
115
|
+
else:
|
|
116
|
+
length = 0
|
|
117
|
+
pattern = []
|
|
118
|
+
|
|
119
|
+
node_count = read_multiple_bytes(file_obj)
|
|
120
|
+
if node_count > 0:
|
|
121
|
+
# non-leaf; load its child nodes
|
|
122
|
+
nodes: list[FlirtNode] = [None] * node_count # type: ignore
|
|
123
|
+
for i in range(node_count):
|
|
124
|
+
nn = self.parse_tree(file_obj)
|
|
125
|
+
nodes[i] = nn
|
|
126
|
+
return FlirtNode(nodes, [], length, pattern)
|
|
127
|
+
# leaf
|
|
128
|
+
modules = self.parse_modules(file_obj)
|
|
129
|
+
return FlirtNode([], modules, length, pattern)
|
|
130
|
+
|
|
131
|
+
def parse_public_function(self, file_obj, offset: int) -> tuple[FlirtFunction, int, int]:
|
|
132
|
+
off = read_multiple_bytes(file_obj) if self.version >= 9 else read_max_2_bytes(file_obj)
|
|
133
|
+
off += offset
|
|
134
|
+
|
|
135
|
+
local = False # is it a local function?
|
|
136
|
+
collision = False # is it an unresolved collision?
|
|
137
|
+
|
|
138
|
+
flags = file_obj.read(1)[0]
|
|
139
|
+
if flags < 0x20:
|
|
140
|
+
local = bool(flags & FlirtFunctionFlag.FUNCTION_LOCAL)
|
|
141
|
+
collision = bool(flags & FlirtFunctionFlag.FUNCTION_UNRESOLVED_COLLISION)
|
|
142
|
+
next_byte = file_obj.read(1)[0]
|
|
143
|
+
else:
|
|
144
|
+
next_byte = flags
|
|
145
|
+
|
|
146
|
+
name_lst = []
|
|
147
|
+
name_end = False # in case the function name is too long...
|
|
148
|
+
for _ in range(1024): # max length of a function name
|
|
149
|
+
if next_byte < 0x20:
|
|
150
|
+
name_end = True
|
|
151
|
+
break
|
|
152
|
+
name_lst.append(next_byte)
|
|
153
|
+
next_byte = file_obj.read(1)[0]
|
|
154
|
+
|
|
155
|
+
name = bytes(name_lst).decode("utf-8")
|
|
156
|
+
if not name_end:
|
|
157
|
+
name = name + "..."
|
|
158
|
+
return FlirtFunction(name, off, local, collision), off, next_byte
|
|
159
|
+
|
|
160
|
+
def parse_referenced_functions(self, file_obj) -> list[FlirtFunction]:
|
|
161
|
+
func_count = file_obj.read(1)[0] if self.version >= 8 else 1
|
|
162
|
+
lst = []
|
|
163
|
+
for _ in range(func_count):
|
|
164
|
+
off = read_multiple_bytes(file_obj) if self.version >= 9 else read_max_2_bytes(file_obj)
|
|
165
|
+
name_len = file_obj.read(1)[0]
|
|
166
|
+
if name_len == 0:
|
|
167
|
+
name_len = read_multiple_bytes(file_obj)
|
|
168
|
+
if name_len > 1024:
|
|
169
|
+
raise FlirtSignatureError(f"Function name too long: {name_len}")
|
|
170
|
+
name_bytes = file_obj.read(name_len)
|
|
171
|
+
if len(name_bytes) < name_len:
|
|
172
|
+
raise FlirtSignatureError("Unexpected EOF")
|
|
173
|
+
name = name_bytes.decode("utf-8").rstrip("\x00")
|
|
174
|
+
lst.append(FlirtFunction(name, off, False, False))
|
|
175
|
+
return lst
|
|
176
|
+
|
|
177
|
+
def parse_tail_bytes(self, file_obj) -> list[tuple[int, int]]:
|
|
178
|
+
bytes_count = file_obj.read(1)[0] if self.version >= 8 else 1
|
|
179
|
+
lst = []
|
|
180
|
+
for _ in range(bytes_count):
|
|
181
|
+
off = read_multiple_bytes(file_obj) if self.version >= 9 else read_max_2_bytes(file_obj)
|
|
182
|
+
value = file_obj.read(1)[0]
|
|
183
|
+
lst.append((off, value))
|
|
184
|
+
return lst
|
|
185
|
+
|
|
186
|
+
def parse_modules(self, file_obj) -> list[FlirtModule]:
|
|
187
|
+
modules = []
|
|
188
|
+
while True:
|
|
189
|
+
crc_len = file_obj.read(1)[0]
|
|
190
|
+
crc = struct.unpack(">H", file_obj.read(2))[0]
|
|
191
|
+
|
|
192
|
+
while True:
|
|
193
|
+
# parse all modules with the same CRC
|
|
194
|
+
module, flags = self.parse_module(file_obj)
|
|
195
|
+
module.crc_len = crc_len
|
|
196
|
+
module.crc = crc
|
|
197
|
+
modules.append(module)
|
|
198
|
+
if flags & FlirtParseFlag.PARSE_MORE_MODULES_WITH_SAME_CRC == 0:
|
|
199
|
+
break
|
|
200
|
+
|
|
201
|
+
# same crc length but different crc
|
|
202
|
+
if flags & FlirtParseFlag.PARSE_MORE_MODULES == 0:
|
|
203
|
+
break
|
|
204
|
+
return modules
|
|
205
|
+
|
|
206
|
+
def parse_module(self, file_obj) -> tuple[FlirtModule, int]:
|
|
207
|
+
length = read_multiple_bytes(file_obj) if self.version >= 9 else read_max_2_bytes(file_obj)
|
|
208
|
+
pub_funcs = []
|
|
209
|
+
off = 0
|
|
210
|
+
while True:
|
|
211
|
+
func, off, flags = self.parse_public_function(file_obj, off)
|
|
212
|
+
pub_funcs.append(func)
|
|
213
|
+
if flags & FlirtParseFlag.PARSE_MORE_PUBLIC_NAMES == 0:
|
|
214
|
+
break
|
|
215
|
+
|
|
216
|
+
tail_bytes: list[tuple[int, int]] = []
|
|
217
|
+
if flags & FlirtParseFlag.PARSE_READ_TAIL_BYTES:
|
|
218
|
+
tail_bytes = self.parse_tail_bytes(file_obj)
|
|
219
|
+
|
|
220
|
+
ref_funcs = []
|
|
221
|
+
if flags & FlirtParseFlag.PARSE_READ_REFERENCED_FUNCTIONS:
|
|
222
|
+
ref_funcs = self.parse_referenced_functions(file_obj)
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
FlirtModule(
|
|
226
|
+
length,
|
|
227
|
+
0, # back-filled in its caller
|
|
228
|
+
0, # back-filled in its caller
|
|
229
|
+
pub_funcs,
|
|
230
|
+
ref_funcs,
|
|
231
|
+
tail_bytes,
|
|
232
|
+
),
|
|
233
|
+
flags,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
@staticmethod
|
|
237
|
+
def parse_variant_mask(file_obj, length: int) -> int:
|
|
238
|
+
if length < 0x10:
|
|
239
|
+
return read_max_2_bytes(file_obj)
|
|
240
|
+
if length <= 0x20:
|
|
241
|
+
return read_multiple_bytes(file_obj)
|
|
242
|
+
if length <= 0x40:
|
|
243
|
+
return (read_multiple_bytes(file_obj) << 32) | read_multiple_bytes(file_obj)
|
|
244
|
+
raise FlirtSignatureError(f"Unexpected variant mask length: {length}")
|
|
245
|
+
|
|
246
|
+
@staticmethod
|
|
247
|
+
def is_bit_set_be(mask: int, mask_len: int, bit_offset: int) -> bool:
|
|
248
|
+
assert mask_len > bit_offset
|
|
249
|
+
return mask & (1 << (mask_len - bit_offset - 1)) != 0
|
|
250
|
+
|
|
251
|
+
@staticmethod
|
|
252
|
+
def parse_node(file_obj, length: int, variant_mask: int) -> list[int]:
|
|
253
|
+
pattern = [-1] * length
|
|
254
|
+
for i in range(length):
|
|
255
|
+
if not FlirtSignatureParsed.is_bit_set_be(variant_mask, length, i):
|
|
256
|
+
pattern[i] = file_obj.read(1)[0]
|
|
257
|
+
return pattern
|
|
258
|
+
|
|
259
|
+
@classmethod
|
|
260
|
+
def parse(cls, file_obj) -> FlirtSignatureParsed:
|
|
261
|
+
"""
|
|
262
|
+
Parse a FLIRT signature file.
|
|
263
|
+
|
|
264
|
+
The following struct definitions come from radare2
|
|
265
|
+
|
|
266
|
+
// FLIRT v5+
|
|
267
|
+
ut8 magic[6];
|
|
268
|
+
ut8 version;
|
|
269
|
+
ut8 arch;
|
|
270
|
+
ut32 file_types;
|
|
271
|
+
ut16 os_types;
|
|
272
|
+
ut16 app_types;
|
|
273
|
+
ut16 features;
|
|
274
|
+
ut16 old_n_functions;
|
|
275
|
+
ut16 crc16;
|
|
276
|
+
ut8 ctype[12];
|
|
277
|
+
ut8 library_name_len;
|
|
278
|
+
ut16 ctypes_crc16;
|
|
279
|
+
|
|
280
|
+
// FLIRT v6+
|
|
281
|
+
ut32 nfuncs;
|
|
282
|
+
|
|
283
|
+
// FLIRT v8+
|
|
284
|
+
ut16 pattern_size;
|
|
285
|
+
|
|
286
|
+
// FLIRT v10
|
|
287
|
+
ut16 unknown;
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
struct_str = "<6s B B I H H H H H 12s B H".replace(" ", "")
|
|
291
|
+
sz = struct.calcsize(struct_str)
|
|
292
|
+
header_bytes = file_obj.read(sz)
|
|
293
|
+
if len(header_bytes) != sz:
|
|
294
|
+
raise FlirtSignatureError
|
|
295
|
+
unpacked = struct.unpack(struct_str, header_bytes)
|
|
296
|
+
|
|
297
|
+
# sanity check
|
|
298
|
+
if unpacked[0] != b"IDASGN":
|
|
299
|
+
raise FlirtSignatureError("Unexpected magic bytes")
|
|
300
|
+
|
|
301
|
+
version = unpacked[1]
|
|
302
|
+
if version < 5:
|
|
303
|
+
raise FlirtSignatureError("Unsupported FLIRT signature version")
|
|
304
|
+
|
|
305
|
+
if version >= 6:
|
|
306
|
+
# nfuncs
|
|
307
|
+
data = file_obj.read(4)
|
|
308
|
+
if len(data) != 4:
|
|
309
|
+
raise FlirtSignatureError("Unexpected EOF")
|
|
310
|
+
nfuncs = struct.unpack("<I", data)[0]
|
|
311
|
+
else:
|
|
312
|
+
nfuncs = None
|
|
313
|
+
if version >= 8:
|
|
314
|
+
# pattern_size
|
|
315
|
+
data = file_obj.read(2)
|
|
316
|
+
if len(data) != 2:
|
|
317
|
+
raise FlirtSignatureError("Unexpected EOF")
|
|
318
|
+
pattern_size = struct.unpack("<H", data)[0]
|
|
319
|
+
else:
|
|
320
|
+
pattern_size = None
|
|
321
|
+
|
|
322
|
+
if version >= 10:
|
|
323
|
+
# unknown
|
|
324
|
+
data = file_obj.read(2)
|
|
325
|
+
if len(data) != 2:
|
|
326
|
+
raise FlirtSignatureError("Unexpected EOF")
|
|
327
|
+
|
|
328
|
+
libname_len = unpacked[10]
|
|
329
|
+
libname = file_obj.read(libname_len).decode("utf-8")
|
|
330
|
+
|
|
331
|
+
obj = cls(
|
|
332
|
+
version=version,
|
|
333
|
+
arch=unpacked[2],
|
|
334
|
+
file_types=unpacked[3],
|
|
335
|
+
os_types=unpacked[4],
|
|
336
|
+
app_types=unpacked[5],
|
|
337
|
+
features=unpacked[6],
|
|
338
|
+
crc=unpacked[7],
|
|
339
|
+
ctype=unpacked[8],
|
|
340
|
+
ctypes_crc=unpacked[11],
|
|
341
|
+
nfuncs=nfuncs,
|
|
342
|
+
pattern_size=pattern_size,
|
|
343
|
+
libname=libname,
|
|
344
|
+
root=None,
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
# is it compressed?
|
|
348
|
+
if obj.features & FlirtFeatureFlag.FEATURE_COMPRESSED:
|
|
349
|
+
data = file_obj.read()
|
|
350
|
+
decompressed = BytesIO(zlib.decompress(data))
|
|
351
|
+
file_obj = decompressed
|
|
352
|
+
|
|
353
|
+
root = obj.parse_tree(file_obj, root=True)
|
|
354
|
+
|
|
355
|
+
obj.root = root
|
|
356
|
+
return obj
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Util functions that are mostly rewrite of the original code in redare2
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import struct
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def read_short(file_obj) -> int:
|
|
7
|
+
return struct.unpack(">H", file_obj.read(2))[0]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def read_word(file_obj) -> int:
|
|
11
|
+
return struct.unpack(">I", file_obj.read(4))[0]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def read_max_2_bytes(file_obj) -> int:
|
|
15
|
+
b = file_obj.read(1)[0]
|
|
16
|
+
if b & 0x80 != 0x80:
|
|
17
|
+
return b
|
|
18
|
+
return ((b & 0x7F) << 8) + file_obj.read(1)[0]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def read_multiple_bytes(file_obj) -> int:
|
|
22
|
+
b = file_obj.read(1)[0]
|
|
23
|
+
if b & 0x80 != 0x80:
|
|
24
|
+
return b
|
|
25
|
+
if b & 0xC0 != 0xC0:
|
|
26
|
+
return ((b & 0x7F) << 8) + file_obj.read(1)[0]
|
|
27
|
+
if b & 0xE0 != 0xE0:
|
|
28
|
+
b = ((b & 0x3F) << 24) + (file_obj.read(1)[0] << 16)
|
|
29
|
+
b += read_short(file_obj)
|
|
30
|
+
return b
|
|
31
|
+
return read_word(file_obj)
|
|
@@ -7,6 +7,7 @@ import re
|
|
|
7
7
|
import logging
|
|
8
8
|
from collections import defaultdict
|
|
9
9
|
|
|
10
|
+
from archinfo.arch_arm import is_arm_arch
|
|
10
11
|
import pyvex
|
|
11
12
|
|
|
12
13
|
from angr.analyses import ForwardAnalysis, visitors
|
|
@@ -16,6 +17,7 @@ from angr.knowledge_plugins import Function
|
|
|
16
17
|
from angr.block import BlockNode
|
|
17
18
|
from angr.errors import SimTranslationError
|
|
18
19
|
from angr.calling_conventions import SimStackArg
|
|
20
|
+
|
|
19
21
|
from .analysis import Analysis
|
|
20
22
|
|
|
21
23
|
try:
|
|
@@ -381,6 +383,10 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
|
|
|
381
383
|
block_start_addr = func.addr if func is not None else block.addr # type: ignore
|
|
382
384
|
self._reg_value_at_block_start[block_start_addr] = initial_reg_values
|
|
383
385
|
|
|
386
|
+
self._itstate_regoffset = None
|
|
387
|
+
if is_arm_arch(self.project.arch):
|
|
388
|
+
self._itstate_regoffset = self.project.arch.registers["itstate"][0]
|
|
389
|
+
|
|
384
390
|
_l.debug("Running on function %r", self._func)
|
|
385
391
|
self._analyze()
|
|
386
392
|
|
|
@@ -617,18 +623,43 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
|
|
|
617
623
|
and is_alignment_mask(arg1_expr.val)
|
|
618
624
|
):
|
|
619
625
|
return arg0_expr
|
|
626
|
+
# also handle bitwise-and between constants
|
|
627
|
+
if isinstance(arg0_expr, Constant) and isinstance(arg1_expr, Constant):
|
|
628
|
+
return Constant(arg0_expr.val & arg1_expr.val)
|
|
629
|
+
elif expr.op.startswith("Iop_Xor"):
|
|
630
|
+
# handle bitwise-xor between constants
|
|
631
|
+
arg0_expr = _resolve_expr(arg0)
|
|
632
|
+
arg1_expr = _resolve_expr(arg1)
|
|
633
|
+
if isinstance(arg0_expr, Constant) and isinstance(arg1_expr, Constant):
|
|
634
|
+
return Constant(arg0_expr.val ^ arg1_expr.val)
|
|
620
635
|
elif expr.op.startswith("Iop_CmpEQ"):
|
|
621
636
|
arg0_expr = _resolve_expr(arg0)
|
|
622
637
|
arg1_expr = _resolve_expr(arg1)
|
|
623
638
|
if isinstance(arg0_expr, (Register, OffsetVal)) and isinstance(arg1_expr, (Register, OffsetVal)):
|
|
624
639
|
return Eq(arg0_expr, arg1_expr)
|
|
640
|
+
elif expr.op.startswith("Iop_CmpNE"):
|
|
641
|
+
arg0_expr = _resolve_expr(arg0)
|
|
642
|
+
arg1_expr = _resolve_expr(arg1)
|
|
643
|
+
if isinstance(arg0_expr, Constant) and isinstance(arg1_expr, Constant):
|
|
644
|
+
return Constant(1 if arg0_expr.val == arg1_expr.val else 0)
|
|
645
|
+
elif expr.op.startswith("Iop_Shr"):
|
|
646
|
+
arg0_expr = _resolve_expr(arg0)
|
|
647
|
+
arg1_expr = _resolve_expr(arg1)
|
|
648
|
+
if isinstance(arg0_expr, Constant) and isinstance(arg1_expr, Constant):
|
|
649
|
+
return Constant(arg0_expr.val >> arg1_expr.val)
|
|
625
650
|
raise CouldNotResolveException
|
|
626
651
|
if type(expr) is pyvex.IRExpr.RdTmp and expr.tmp in tmps and tmps[expr.tmp] is not None:
|
|
627
652
|
return tmps[expr.tmp]
|
|
628
653
|
if type(expr) is pyvex.IRExpr.Const:
|
|
629
654
|
return Constant(expr.con.value)
|
|
630
655
|
if type(expr) is pyvex.IRExpr.Get:
|
|
656
|
+
if self._itstate_regoffset is not None and expr.offset == self._itstate_regoffset:
|
|
657
|
+
return Constant(0)
|
|
631
658
|
return state.get(expr.offset)
|
|
659
|
+
if type(expr) is pyvex.IRExpr.ITE:
|
|
660
|
+
cond = _resolve_expr(expr.cond)
|
|
661
|
+
if isinstance(cond, Constant):
|
|
662
|
+
return _resolve_expr(expr.iftrue) if cond.val == 1 else _resolve_expr(expr.iffalse)
|
|
632
663
|
if type(expr) is pyvex.IRExpr.Unop:
|
|
633
664
|
m = IROP_CONVERT_REGEX.match(expr.op)
|
|
634
665
|
if m is not None:
|
|
@@ -646,6 +677,9 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
|
|
|
646
677
|
if isinstance(v, Eq):
|
|
647
678
|
return v
|
|
648
679
|
return TOP
|
|
680
|
+
elif type(expr) is pyvex.IRExpr.CCall and expr.callee.name == "armg_calculate_condition":
|
|
681
|
+
# this is a hack for handling ARM THUMB conditional instructions and may not always work...
|
|
682
|
+
return Constant(0)
|
|
649
683
|
elif self.track_mem and type(expr) is pyvex.IRExpr.Load:
|
|
650
684
|
return state.load(_resolve_expr(expr.addr))
|
|
651
685
|
raise CouldNotResolveException
|
angr/analyses/typehoon/lifter.py
CHANGED
|
@@ -11,8 +11,10 @@ from angr.sim_type import (
|
|
|
11
11
|
SimTypePointer,
|
|
12
12
|
SimStruct,
|
|
13
13
|
SimTypeArray,
|
|
14
|
+
SimTypeFloat,
|
|
15
|
+
SimTypeDouble,
|
|
14
16
|
)
|
|
15
|
-
from .typeconsts import BottomType, Int8, Int16, Int32, Int64, Pointer32, Pointer64, Struct, Array
|
|
17
|
+
from .typeconsts import BottomType, Int8, Int16, Int32, Int64, Pointer32, Pointer64, Struct, Array, Float32, Float64
|
|
16
18
|
|
|
17
19
|
if TYPE_CHECKING:
|
|
18
20
|
from .typeconsts import TypeConstant
|
|
@@ -79,6 +81,12 @@ class TypeLifter:
|
|
|
79
81
|
elem_type = self.lift(ty.elem_type)
|
|
80
82
|
return Array(elem_type, count=ty.length)
|
|
81
83
|
|
|
84
|
+
def _lift_SimTypeFloat(self, ty: SimTypeFloat) -> Float32: # pylint:disable=unused-argument,no-self-use
|
|
85
|
+
return Float32()
|
|
86
|
+
|
|
87
|
+
def _lift_SimTypeDouble(self, ty: SimTypeDouble) -> Float64: # pylint:disable=unused-argument,no-self-use
|
|
88
|
+
return Float64()
|
|
89
|
+
|
|
82
90
|
|
|
83
91
|
_mapping = {
|
|
84
92
|
SimTypeChar: TypeLifter._lift_SimTypeChar,
|
|
@@ -89,4 +97,6 @@ _mapping = {
|
|
|
89
97
|
SimTypePointer: TypeLifter._lift_SimTypePointer,
|
|
90
98
|
SimStruct: TypeLifter._lift_SimStruct,
|
|
91
99
|
SimTypeArray: TypeLifter._lift_SimTypeArray,
|
|
100
|
+
SimTypeFloat: TypeLifter._lift_SimTypeFloat,
|
|
101
|
+
SimTypeDouble: TypeLifter._lift_SimTypeDouble,
|
|
92
102
|
}
|
|
@@ -41,6 +41,9 @@ from .typeconsts import (
|
|
|
41
41
|
Array,
|
|
42
42
|
Function,
|
|
43
43
|
int_type,
|
|
44
|
+
Float,
|
|
45
|
+
Float32,
|
|
46
|
+
Float64,
|
|
44
47
|
)
|
|
45
48
|
from .variance import Variance
|
|
46
49
|
from .dfa import DFAConstraintSolver, EmptyEpsilonNFAError
|
|
@@ -60,6 +63,9 @@ PRIMITIVE_TYPES = {
|
|
|
60
63
|
BottomType(),
|
|
61
64
|
Struct(),
|
|
62
65
|
Array(),
|
|
66
|
+
Float(),
|
|
67
|
+
Float32(),
|
|
68
|
+
Float64(),
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
Top_ = TopType()
|
|
@@ -73,6 +79,9 @@ Pointer64_ = Pointer64()
|
|
|
73
79
|
Pointer32_ = Pointer32()
|
|
74
80
|
Struct_ = Struct()
|
|
75
81
|
Array_ = Array()
|
|
82
|
+
Float_ = Float()
|
|
83
|
+
Float32_ = Float32()
|
|
84
|
+
Float64_ = Float64()
|
|
76
85
|
|
|
77
86
|
# lattice for 64-bit binaries
|
|
78
87
|
BASE_LATTICE_64 = networkx.DiGraph()
|
|
@@ -161,6 +161,12 @@ class TypeTranslator:
|
|
|
161
161
|
self._has_nonexistent_ref = True
|
|
162
162
|
return SimTypeTempRef(tc.typevar)
|
|
163
163
|
|
|
164
|
+
def _translate_Float32(self, tc: typeconsts.Float32) -> sim_type.SimTypeFloat: # pylint:disable=unused-argument
|
|
165
|
+
return sim_type.SimTypeFloat().with_arch(self.arch)
|
|
166
|
+
|
|
167
|
+
def _translate_Float64(self, tc: typeconsts.Float64) -> sim_type.SimTypeDouble: # pylint:disable=unused-argument
|
|
168
|
+
return sim_type.SimTypeDouble().with_arch(self.arch)
|
|
169
|
+
|
|
164
170
|
#
|
|
165
171
|
# Backpatching
|
|
166
172
|
#
|
|
@@ -229,6 +235,12 @@ class TypeTranslator:
|
|
|
229
235
|
return typeconsts.Pointer64(base)
|
|
230
236
|
raise TypeError(f"Unsupported pointer size {self.arch.bits}")
|
|
231
237
|
|
|
238
|
+
def _translate_SimTypeFloat(self, st: sim_type.SimTypeFloat) -> typeconsts.Float32:
|
|
239
|
+
return typeconsts.Float32()
|
|
240
|
+
|
|
241
|
+
def _translate_SimTypeDouble(self, st: sim_type.SimTypeDouble) -> typeconsts.Float64:
|
|
242
|
+
return typeconsts.Float64()
|
|
243
|
+
|
|
232
244
|
|
|
233
245
|
TypeConstHandlers = {
|
|
234
246
|
typeconsts.Pointer64: TypeTranslator._translate_Pointer64,
|
|
@@ -243,6 +255,8 @@ TypeConstHandlers = {
|
|
|
243
255
|
typeconsts.Int256: TypeTranslator._translate_Int256,
|
|
244
256
|
typeconsts.Int512: TypeTranslator._translate_Int512,
|
|
245
257
|
typeconsts.TypeVariableReference: TypeTranslator._translate_TypeVariableReference,
|
|
258
|
+
typeconsts.Float32: TypeTranslator._translate_Float32,
|
|
259
|
+
typeconsts.Float64: TypeTranslator._translate_Float64,
|
|
246
260
|
}
|
|
247
261
|
|
|
248
262
|
|
|
@@ -257,4 +271,6 @@ SimTypeHandlers = {
|
|
|
257
271
|
sim_type.SimTypeInt512: TypeTranslator._translate_SimTypeInt512,
|
|
258
272
|
sim_type.SimStruct: TypeTranslator._translate_SimStruct,
|
|
259
273
|
sim_type.SimTypeArray: TypeTranslator._translate_SimTypeArray,
|
|
274
|
+
sim_type.SimTypeFloat: TypeTranslator._translate_SimTypeFloat,
|
|
275
|
+
sim_type.SimTypeDouble: TypeTranslator._translate_SimTypeDouble,
|
|
260
276
|
}
|
|
@@ -114,23 +114,23 @@ class Int512(Int):
|
|
|
114
114
|
return "int512"
|
|
115
115
|
|
|
116
116
|
|
|
117
|
-
class
|
|
117
|
+
class Float(TypeConstant):
|
|
118
118
|
def __repr__(self, memo=None) -> str:
|
|
119
119
|
return "floatbase"
|
|
120
120
|
|
|
121
121
|
|
|
122
|
-
class Float
|
|
122
|
+
class Float32(Float):
|
|
123
123
|
SIZE = 4
|
|
124
124
|
|
|
125
125
|
def __repr__(self, memo=None):
|
|
126
|
-
return "
|
|
126
|
+
return "float32"
|
|
127
127
|
|
|
128
128
|
|
|
129
|
-
class
|
|
129
|
+
class Float64(Float):
|
|
130
130
|
SIZE = 8
|
|
131
131
|
|
|
132
132
|
def __repr__(self, memo=None):
|
|
133
|
-
return "
|
|
133
|
+
return "float64"
|
|
134
134
|
|
|
135
135
|
|
|
136
136
|
class Pointer(TypeConstant):
|
|
@@ -317,9 +317,9 @@ def int_type(bits: int) -> Int:
|
|
|
317
317
|
raise TypeError(f"Not a known size of int: {bits}")
|
|
318
318
|
|
|
319
319
|
|
|
320
|
-
def float_type(bits: int) ->
|
|
320
|
+
def float_type(bits: int) -> Float | None:
|
|
321
321
|
if bits == 32:
|
|
322
|
-
return
|
|
322
|
+
return Float32()
|
|
323
323
|
if bits == 64:
|
|
324
|
-
return
|
|
324
|
+
return Float64()
|
|
325
325
|
return None
|
angr/analyses/vfg.py
CHANGED
|
@@ -1547,7 +1547,7 @@ class VFG(ForwardAnalysis[SimState, VFGNode, VFGJob, BlockID], Analysis): # pyl
|
|
|
1547
1547
|
reg_sp_si = self._create_stack_region(successor_state, successor_addr)
|
|
1548
1548
|
|
|
1549
1549
|
# Save the new sp register
|
|
1550
|
-
new_reg_sp_expr = reg_sp_si.annotate(claripy.annotation.RegionAnnotation("global", 0
|
|
1550
|
+
new_reg_sp_expr = reg_sp_si.annotate(claripy.annotation.RegionAnnotation("global", 0))
|
|
1551
1551
|
successor_state.regs.sp = new_reg_sp_expr
|
|
1552
1552
|
|
|
1553
1553
|
new_job = VFGJob(
|
angr/block.py
CHANGED
|
@@ -433,9 +433,9 @@ class Block(Serializable):
|
|
|
433
433
|
|
|
434
434
|
@property
|
|
435
435
|
def instructions(self) -> int:
|
|
436
|
-
if not self._instructions and self._vex is None:
|
|
437
|
-
# initialize from VEX
|
|
438
|
-
_ = self.
|
|
436
|
+
if not self._instructions and self._vex is None and self._vex_nostmt is None:
|
|
437
|
+
# initialize from VEX, but we do not need statements to know instructions
|
|
438
|
+
_ = self.vex_nostmt
|
|
439
439
|
|
|
440
440
|
assert self._instructions is not None
|
|
441
441
|
return self._instructions
|
|
@@ -446,9 +446,9 @@ class Block(Serializable):
|
|
|
446
446
|
# hooks and other pseudo-functions
|
|
447
447
|
return []
|
|
448
448
|
|
|
449
|
-
if not self._instruction_addrs and self._vex is None:
|
|
450
|
-
# initialize instruction addrs
|
|
451
|
-
_ = self.
|
|
449
|
+
if not self._instruction_addrs and self._vex is None and self._vex_nostmt is None:
|
|
450
|
+
# initialize instruction addrs, but we do not need statements
|
|
451
|
+
_ = self.vex_nostmt
|
|
452
452
|
|
|
453
453
|
return self._instruction_addrs
|
|
454
454
|
|
|
@@ -160,6 +160,15 @@ def concretize_fscale(state, args):
|
|
|
160
160
|
return claripy.FPV(arg_x * math.pow(2, arg_y), claripy.FSORT_DOUBLE)
|
|
161
161
|
|
|
162
162
|
|
|
163
|
+
def concretize_fsqrt32(state, args):
|
|
164
|
+
# Concretize floating point square root. Z3 does support square root but unsure if that includes floating point
|
|
165
|
+
arg_1 = state.solver.eval(args[1])
|
|
166
|
+
if arg_1 < 0 or math.isnan(arg_1):
|
|
167
|
+
return claripy.FPV(math.nan, claripy.FSORT_FLOAT)
|
|
168
|
+
|
|
169
|
+
return claripy.FPV(math.sqrt(arg_1), claripy.FSORT_FLOAT)
|
|
170
|
+
|
|
171
|
+
|
|
163
172
|
def concretize_fsqrt(state, args):
|
|
164
173
|
# Concretize floating point square root. Z3 does support square root but unsure if that includes floating point
|
|
165
174
|
arg_1 = state.solver.eval(args[1])
|
|
@@ -365,6 +374,7 @@ concretizers = {
|
|
|
365
374
|
"Iop_Yl2xF64": concretize_yl2x,
|
|
366
375
|
"Iop_ScaleF64": concretize_fscale,
|
|
367
376
|
"Iop_2xm1F64": concretize_2xm1,
|
|
377
|
+
"Iop_SqrtF32": concretize_fsqrt32,
|
|
368
378
|
"Iop_SqrtF64": concretize_fsqrt,
|
|
369
379
|
"Iop_CosF64": concretize_trig_cos,
|
|
370
380
|
"Iop_SinF64": concretize_trig_sin,
|