angr 9.2.146__py3-none-win_amd64.whl → 9.2.148__py3-none-win_amd64.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.

Files changed (67) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/analysis.py +3 -11
  3. angr/analyses/bindiff.py +343 -68
  4. angr/analyses/calling_convention/fact_collector.py +5 -4
  5. angr/analyses/calling_convention/utils.py +1 -0
  6. angr/analyses/cfg/cfg_arch_options.py +10 -0
  7. angr/analyses/cfg/cfg_base.py +42 -74
  8. angr/analyses/cfg/cfg_emulated.py +12 -12
  9. angr/analyses/cfg/cfg_fast.py +39 -20
  10. angr/analyses/cfg/cfg_fast_soot.py +3 -3
  11. angr/analyses/decompiler/callsite_maker.py +28 -18
  12. angr/analyses/decompiler/clinic.py +4 -4
  13. angr/analyses/decompiler/condition_processor.py +0 -21
  14. angr/analyses/decompiler/counters/call_counter.py +3 -0
  15. angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +1 -1
  16. angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +14 -0
  17. angr/analyses/decompiler/structured_codegen/c.py +5 -5
  18. angr/analyses/decompiler/structuring/phoenix.py +11 -3
  19. angr/analyses/deobfuscator/api_obf_finder.py +5 -1
  20. angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
  21. angr/analyses/flirt/__init__.py +47 -0
  22. angr/analyses/flirt/consts.py +160 -0
  23. angr/analyses/{flirt.py → flirt/flirt.py} +99 -38
  24. angr/analyses/flirt/flirt_function.py +20 -0
  25. angr/analyses/flirt/flirt_matcher.py +351 -0
  26. angr/analyses/flirt/flirt_module.py +32 -0
  27. angr/analyses/flirt/flirt_node.py +23 -0
  28. angr/analyses/flirt/flirt_sig.py +356 -0
  29. angr/analyses/flirt/flirt_utils.py +31 -0
  30. angr/analyses/forward_analysis/visitors/graph.py +0 -8
  31. angr/analyses/identifier/runner.py +1 -1
  32. angr/analyses/reaching_definitions/function_handler.py +4 -4
  33. angr/analyses/reassembler.py +1 -1
  34. angr/analyses/stack_pointer_tracker.py +35 -1
  35. angr/analyses/static_hooker.py +11 -9
  36. angr/analyses/variable_recovery/engine_ail.py +8 -8
  37. angr/analyses/variable_recovery/engine_base.py +2 -0
  38. angr/block.py +6 -6
  39. angr/calling_conventions.py +74 -23
  40. angr/engines/vex/heavy/concretizers.py +10 -0
  41. angr/exploration_techniques/director.py +1 -1
  42. angr/flirt/__init__.py +15 -44
  43. angr/knowledge_plugins/functions/function.py +42 -39
  44. angr/knowledge_plugins/functions/function_manager.py +9 -0
  45. angr/knowledge_plugins/functions/function_parser.py +9 -1
  46. angr/knowledge_plugins/functions/soot_function.py +1 -1
  47. angr/knowledge_plugins/key_definitions/key_definition_manager.py +1 -1
  48. angr/lib/angr_native.dll +0 -0
  49. angr/procedures/definitions/__init__.py +14 -11
  50. angr/procedures/stubs/format_parser.py +1 -1
  51. angr/project.py +23 -29
  52. angr/protos/cfg_pb2.py +14 -25
  53. angr/protos/function_pb2.py +11 -22
  54. angr/protos/primitives_pb2.py +36 -47
  55. angr/protos/variables_pb2.py +28 -39
  56. angr/protos/xrefs_pb2.py +8 -19
  57. angr/sim_type.py +0 -16
  58. angr/simos/cgc.py +1 -1
  59. angr/simos/linux.py +5 -5
  60. angr/simos/windows.py +5 -5
  61. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -1
  62. {angr-9.2.146.dist-info → angr-9.2.148.dist-info}/METADATA +8 -8
  63. {angr-9.2.146.dist-info → angr-9.2.148.dist-info}/RECORD +67 -59
  64. {angr-9.2.146.dist-info → angr-9.2.148.dist-info}/WHEEL +1 -1
  65. {angr-9.2.146.dist-info → angr-9.2.148.dist-info}/entry_points.txt +0 -0
  66. {angr-9.2.146.dist-info → angr-9.2.148.dist-info/licenses}/LICENSE +0 -0
  67. {angr-9.2.146.dist-info → angr-9.2.148.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)
@@ -3,7 +3,6 @@ from typing import TypeVar, Generic
3
3
  from collections.abc import Collection, Iterator
4
4
  from collections import defaultdict
5
5
 
6
- from angr.misc.ux import deprecated
7
6
  from angr.utils.algo import binary_insert
8
7
 
9
8
  NodeType = TypeVar("NodeType")
@@ -94,13 +93,6 @@ class GraphVisitor(Generic[NodeType]):
94
93
 
95
94
  return iter(self.sort_nodes())
96
95
 
97
- @deprecated(replacement="nodes")
98
- def nodes_iter(self):
99
- """
100
- (Deprecated) Return an iterator of nodes following an optimal traversal order. Will be removed in the future.
101
- """
102
- return self.nodes()
103
-
104
96
  # Traversal
105
97
 
106
98
  def reset(self):
@@ -29,7 +29,7 @@ assert len(FLAG_DATA) == 0x1000
29
29
  class Runner:
30
30
  def __init__(self, project, cfg):
31
31
  # this is kind of fucked up
32
- project.simos.syscall_library.update(SIM_LIBRARIES["cgcabi_tracer"])
32
+ project.simos.syscall_library.update(SIM_LIBRARIES["cgcabi_tracer"][0])
33
33
 
34
34
  self.project = project
35
35
  self.cfg = cfg
@@ -401,10 +401,10 @@ class FunctionHandler:
401
401
  )
402
402
  type_collections = []
403
403
  if prototype_libname is not None and prototype_libname in SIM_LIBRARIES:
404
- prototype_lib = SIM_LIBRARIES[prototype_libname]
405
- if prototype_lib.type_collection_names:
406
- for typelib_name in prototype_lib.type_collection_names:
407
- type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
404
+ for prototype_lib in SIM_LIBRARIES[prototype_libname]:
405
+ if prototype_lib.type_collection_names:
406
+ for typelib_name in prototype_lib.type_collection_names:
407
+ type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
408
408
  if type_collections:
409
409
  prototype = dereference_simtype(data.prototype, type_collections).with_arch(state.arch)
410
410
  data.prototype = cast(SimTypeFunction, prototype)
@@ -2410,7 +2410,7 @@ class Reassembler(Analysis):
2410
2410
 
2411
2411
  # collect address of all instructions
2412
2412
  l.debug("Collecting instruction addresses...")
2413
- for cfg_node in self.cfg.nodes():
2413
+ for cfg_node in self.cfg.model.nodes():
2414
2414
  self.all_insn_addrs |= set(cfg_node.instruction_addrs)
2415
2415
 
2416
2416
  # Functions
@@ -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
 
@@ -514,7 +520,7 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
514
520
  # Setting register values to fresh ones will cause problems down the line when merging with normal
515
521
  # register values happen. therefore, we set their values to BOTTOM. these BOTTOMs will be replaced once
516
522
  # a merge with normal blocks happen.
517
- initial_regs = {r: BOTTOM for r in self.reg_offsets}
523
+ initial_regs = dict.fromkeys(self.reg_offsets, BOTTOM)
518
524
 
519
525
  return StackPointerTrackerState(
520
526
  regs=initial_regs, memory={}, is_tracking_memory=self.track_mem, resilient=self._resilient
@@ -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
@@ -21,7 +21,7 @@ class StaticHooker(Analysis):
21
21
  def __init__(self, library, binary=None):
22
22
  self.results = {}
23
23
  try:
24
- lib = SIM_LIBRARIES[library]
24
+ libs = SIM_LIBRARIES[library]
25
25
  except KeyError as err:
26
26
  raise AngrValueError(f"No such library {library}") from err
27
27
 
@@ -36,14 +36,16 @@ class StaticHooker(Analysis):
36
36
  l.debug("Skipping %s at %#x, already hooked", func.name, func.rebased_addr)
37
37
  continue
38
38
 
39
- if lib.has_implementation(func.name):
40
- proc = lib.get(func.name, self.project.arch)
41
- self.results[func.rebased_addr] = proc
42
- if self.project.is_hooked(func.rebased_addr):
43
- l.debug("Skipping %s at %#x, already hooked", func.name, func.rebased_addr)
44
- else:
45
- self.project.hook(func.rebased_addr, proc)
46
- l.info("Hooked %s at %#x", func.name, func.rebased_addr)
39
+ for lib in libs:
40
+ if lib.has_implementation(func.name):
41
+ proc = lib.get(func.name, self.project.arch)
42
+ self.results[func.rebased_addr] = proc
43
+ if self.project.is_hooked(func.rebased_addr):
44
+ l.debug("Skipping %s at %#x, already hooked", func.name, func.rebased_addr)
45
+ else:
46
+ self.project.hook(func.rebased_addr, proc)
47
+ l.info("Hooked %s at %#x", func.name, func.rebased_addr)
48
+ break
47
49
  else:
48
50
  l.debug("Failed to hook %s at %#x", func.name, func.rebased_addr)
49
51
 
@@ -169,10 +169,10 @@ class SimEngineVRAIL(
169
169
 
170
170
  type_collections = []
171
171
  if prototype_libname is not None:
172
- prototype_lib = SIM_LIBRARIES[prototype_libname]
173
- if prototype_lib.type_collection_names:
174
- for typelib_name in prototype_lib.type_collection_names:
175
- type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
172
+ for prototype_lib in SIM_LIBRARIES[prototype_libname]:
173
+ if prototype_lib.type_collection_names:
174
+ for typelib_name in prototype_lib.type_collection_names:
175
+ type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
176
176
 
177
177
  for arg, arg_type in zip(args, prototype.args):
178
178
  if arg.typevar is not None:
@@ -262,10 +262,10 @@ class SimEngineVRAIL(
262
262
 
263
263
  type_collections = []
264
264
  if prototype_libname is not None:
265
- prototype_lib = SIM_LIBRARIES[prototype_libname]
266
- if prototype_lib.type_collection_names:
267
- for typelib_name in prototype_lib.type_collection_names:
268
- type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
265
+ for prototype_lib in SIM_LIBRARIES[prototype_libname]:
266
+ if prototype_lib.type_collection_names:
267
+ for typelib_name in prototype_lib.type_collection_names:
268
+ type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
269
269
 
270
270
  for arg, arg_type in zip(args, prototype.args):
271
271
  if arg.typevar is not None:
@@ -417,6 +417,7 @@ class SimEngineVRBase(
417
417
  vvar.size,
418
418
  ident=self.state.variable_manager[self.func_addr].next_variable_ident("stack"),
419
419
  region=self.func_addr,
420
+ base="bp",
420
421
  )
421
422
  self.state.variable_manager[self.func_addr].add_variable("stack", vvar.stack_offset, variable)
422
423
  elif vvar.was_parameter:
@@ -1079,6 +1080,7 @@ class SimEngineVRBase(
1079
1080
  vvar.size,
1080
1081
  ident=self.state.variable_manager[self.func_addr].next_variable_ident("stack"),
1081
1082
  region=self.func_addr,
1083
+ base="bp",
1082
1084
  )
1083
1085
  value = self.state.annotate_with_variables(value, [(0, variable)])
1084
1086
  self.state.variable_manager[self.func_addr].add_variable("stack", vvar.stack_offset, variable)
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.vex
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.vex
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