angr 9.2.136__py3-none-win_amd64.whl → 9.2.137__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 (60) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/calling_convention/calling_convention.py +2 -1
  3. angr/analyses/calling_convention/fact_collector.py +10 -2
  4. angr/analyses/cfg/cfg_base.py +3 -33
  5. angr/analyses/cfg/cfg_emulated.py +0 -103
  6. angr/analyses/cfg/cfg_fast.py +28 -12
  7. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +15 -0
  8. angr/analyses/class_identifier.py +1 -2
  9. angr/analyses/complete_calling_conventions.py +3 -0
  10. angr/analyses/decompiler/ail_simplifier.py +12 -1
  11. angr/analyses/decompiler/block_simplifier.py +2 -2
  12. angr/analyses/decompiler/ccall_rewriters/__init__.py +2 -0
  13. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
  14. angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +69 -0
  15. angr/analyses/decompiler/clinic.py +77 -65
  16. angr/analyses/decompiler/condition_processor.py +2 -0
  17. angr/analyses/decompiler/decompiler.py +1 -0
  18. angr/analyses/decompiler/dephication/dephication_base.py +2 -0
  19. angr/analyses/decompiler/dephication/rewriting_engine.py +8 -6
  20. angr/analyses/decompiler/dephication/seqnode_dephication.py +10 -1
  21. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +1 -2
  22. angr/analyses/decompiler/sequence_walker.py +6 -2
  23. angr/analyses/decompiler/ssailification/rewriting.py +11 -1
  24. angr/analyses/decompiler/ssailification/rewriting_engine.py +56 -19
  25. angr/analyses/decompiler/ssailification/ssailification.py +13 -3
  26. angr/analyses/decompiler/ssailification/traversal.py +28 -2
  27. angr/analyses/decompiler/ssailification/traversal_state.py +6 -1
  28. angr/analyses/decompiler/structured_codegen/c.py +44 -21
  29. angr/analyses/decompiler/structuring/phoenix.py +117 -14
  30. angr/analyses/decompiler/utils.py +113 -8
  31. angr/analyses/reaching_definitions/function_handler.py +1 -1
  32. angr/analyses/s_liveness.py +5 -1
  33. angr/analyses/s_propagator.py +25 -4
  34. angr/analyses/s_reaching_definitions/s_rda_model.py +2 -1
  35. angr/analyses/s_reaching_definitions/s_rda_view.py +20 -1
  36. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +11 -1
  37. angr/analyses/stack_pointer_tracker.py +26 -16
  38. angr/analyses/variable_recovery/engine_ail.py +19 -7
  39. angr/analyses/variable_recovery/engine_base.py +16 -14
  40. angr/analyses/variable_recovery/engine_vex.py +2 -2
  41. angr/analyses/variable_recovery/variable_recovery_fast.py +22 -1
  42. angr/block.py +59 -20
  43. angr/engines/pcode/emulate.py +1 -1
  44. angr/engines/pcode/lifter.py +31 -18
  45. angr/engines/soot/expressions/__init__.py +2 -4
  46. angr/engines/soot/statements/__init__.py +1 -2
  47. angr/engines/soot/values/__init__.py +1 -2
  48. angr/engines/successors.py +11 -6
  49. angr/engines/vex/lifter.py +9 -6
  50. angr/flirt/build_sig.py +8 -15
  51. angr/knowledge_plugins/functions/function.py +0 -6
  52. angr/knowledge_plugins/functions/soot_function.py +5 -8
  53. angr/knowledge_plugins/variables/variable_manager.py +16 -10
  54. angr/lib/angr_native.dll +0 -0
  55. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/METADATA +7 -7
  56. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/RECORD +60 -59
  57. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/WHEEL +1 -1
  58. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/LICENSE +0 -0
  59. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/entry_points.txt +0 -0
  60. {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,7 @@
7
7
  from __future__ import annotations
8
8
 
9
9
  import logging
10
- from typing import Optional
10
+ from typing import Any, TYPE_CHECKING
11
11
  from collections.abc import Iterable, Sequence
12
12
 
13
13
  import archinfo
@@ -35,6 +35,12 @@ except ImportError:
35
35
  pypcode = None
36
36
 
37
37
 
38
+ if TYPE_CHECKING:
39
+ # this is to make pyright happy; otherwise it believes pypcode is None
40
+ import pypcode
41
+ from pypcode import PcodeOp, Context
42
+
43
+
38
44
  l = logging.getLogger(__name__)
39
45
 
40
46
  IRSB_MAX_SIZE = 400
@@ -130,8 +136,8 @@ class IRSB:
130
136
 
131
137
  _direct_next: bool | None
132
138
  _exit_statements: Sequence[tuple[int, int, ExitStatement]]
133
- _instruction_addresses: Sequence[int] | None
134
- _ops: Sequence[pypcode.PcodeOp] # FIXME: Merge into _statements
139
+ _instruction_addresses: list[int] | None
140
+ _ops: list[PcodeOp] # FIXME: Merge into _statements
135
141
  _size: int | None
136
142
  _statements: Iterable # Note: currently unused
137
143
  _disassembly: PcodeDisassemblerBlock | None
@@ -140,7 +146,7 @@ class IRSB:
140
146
  behaviors: BehaviorFactory | None
141
147
  data_refs: Sequence # Note: currently unused
142
148
  const_vals: Sequence # Note: currently unused
143
- default_exit_target: Optional # Note: currently used
149
+ default_exit_target: Any # Note: currently used
144
150
  jumpkind: str | None
145
151
  next: int | None
146
152
 
@@ -199,7 +205,7 @@ class IRSB:
199
205
  self._direct_next = None
200
206
  self._exit_statements = []
201
207
  self._instruction_addresses = None
202
- self._ops = []
208
+ self._ops: list[PcodeOp] = []
203
209
  self._size = None
204
210
  self._statements = []
205
211
  self.addr = mem_addr
@@ -248,7 +254,7 @@ class IRSB:
248
254
 
249
255
  @property
250
256
  def has_statements(self) -> bool:
251
- return self.statements is not None and self.statements
257
+ return bool(self.statements is not None and self.statements)
252
258
 
253
259
  @property
254
260
  def exit_statements(self) -> Sequence[tuple[int, int, ExitStatement]]:
@@ -320,7 +326,7 @@ class IRSB:
320
326
  return len(self.statements)
321
327
 
322
328
  @property
323
- def offsIP(self) -> int:
329
+ def offsIP(self) -> int | None:
324
330
  return self.arch.ip_offset
325
331
 
326
332
  @property
@@ -459,10 +465,10 @@ class IRSB:
459
465
  jumpkind: str | None = None,
460
466
  direct_next: bool | None = None,
461
467
  size: int | None = None,
462
- ops: Sequence[pypcode.PcodeOp] | None = None,
463
- instruction_addresses: Iterable[int] | None = None,
468
+ ops: list[PcodeOp] | None = None,
469
+ instruction_addresses: list[int] | None = None,
464
470
  exit_statements: Sequence[tuple[int, int, ExitStatement]] | None = None,
465
- default_exit_target: Optional | None = None,
471
+ default_exit_target: Any = None,
466
472
  ) -> None:
467
473
  # pylint: disable=unused-argument
468
474
  self._statements = statements if statements is not None else []
@@ -490,7 +496,7 @@ class IRSB:
490
496
  )
491
497
 
492
498
  @property
493
- def statements(self) -> Iterable:
499
+ def statements(self) -> list:
494
500
  # FIXME: For compatibility, may want to implement Ist_IMark and
495
501
  # pyvex.IRStmt.Exit to ease analyses.
496
502
  l.debug("Returning empty statements list!")
@@ -807,7 +813,7 @@ class PcodeBasicBlockLifter:
807
813
  Lifts basic blocks to P-code
808
814
  """
809
815
 
810
- context: pypcode.Context
816
+ context: Context
811
817
  behaviors: BehaviorFactory
812
818
 
813
819
  def __init__(self, arch: archinfo.Arch):
@@ -1032,7 +1038,7 @@ class PcodeLifterEngineMixin(SimEngineBase):
1032
1038
  self,
1033
1039
  addr: int | None = None,
1034
1040
  state: SimState | None = None,
1035
- clemory: cle.Clemory | None = None,
1041
+ clemory: cle.Clemory | cle.ClemoryReadOnlyView | None = None,
1036
1042
  insn_bytes: bytes | None = None,
1037
1043
  arch: archinfo.Arch | None = None,
1038
1044
  size: int | None = None,
@@ -1047,7 +1053,7 @@ class PcodeLifterEngineMixin(SimEngineBase):
1047
1053
  load_from_ro_regions: bool = False,
1048
1054
  cross_insn_opt: bool | None = None,
1049
1055
  const_prop: bool | None = None,
1050
- ):
1056
+ ) -> IRSB:
1051
1057
  """
1052
1058
  Temporary compatibility interface for integration with block code.
1053
1059
  """
@@ -1075,7 +1081,7 @@ class PcodeLifterEngineMixin(SimEngineBase):
1075
1081
  self,
1076
1082
  addr: int | None = None,
1077
1083
  state: SimState | None = None,
1078
- clemory: cle.Clemory | None = None,
1084
+ clemory: cle.Clemory | cle.ClemoryReadOnlyView | None = None,
1079
1085
  insn_bytes: bytes | None = None,
1080
1086
  arch: archinfo.Arch | None = None,
1081
1087
  size: int | None = None,
@@ -1090,7 +1096,7 @@ class PcodeLifterEngineMixin(SimEngineBase):
1090
1096
  load_from_ro_regions: bool = False,
1091
1097
  cross_insn_opt: bool | None = None,
1092
1098
  const_prop: bool | None = None,
1093
- ):
1099
+ ) -> IRSB:
1094
1100
  """
1095
1101
  Lift an IRSB.
1096
1102
 
@@ -1137,6 +1143,7 @@ class PcodeLifterEngineMixin(SimEngineBase):
1137
1143
 
1138
1144
  # phase 1: parameter defaults
1139
1145
  if addr is None:
1146
+ assert state is not None
1140
1147
  addr = state.solver.eval(state._ip)
1141
1148
  if size is not None:
1142
1149
  size = min(size, IRSB_MAX_SIZE)
@@ -1158,6 +1165,7 @@ class PcodeLifterEngineMixin(SimEngineBase):
1158
1165
  " disabled."
1159
1166
  )
1160
1167
  opt_level = 0
1168
+ assert state is not None
1161
1169
  if state and o.OPTIMIZE_IR in state.options:
1162
1170
  state.options.remove(o.OPTIMIZE_IR)
1163
1171
  if skip_stmts is not True:
@@ -1278,13 +1286,18 @@ class PcodeLifterEngineMixin(SimEngineBase):
1278
1286
  )
1279
1287
  return irsb
1280
1288
 
1289
+ raise SimEngineError("Unreachable code reached")
1281
1290
  # phase x: error handling
1282
1291
  except PyVEXError as e:
1283
1292
  l.debug("Translation error at %#x", addr)
1284
1293
  raise SimTranslationError("Unable to translate bytecode") from e
1285
1294
 
1286
1295
  def _load_bytes(
1287
- self, addr: int, max_size: int, state: SimState | None = None, clemory: cle.Clemory | None = None
1296
+ self,
1297
+ addr: int,
1298
+ max_size: int,
1299
+ state: SimState | None = None,
1300
+ clemory: cle.Clemory | cle.ClemoryReadOnlyView | None = None,
1288
1301
  ) -> tuple[bytes, int, int]:
1289
1302
  if clemory is None and state is None:
1290
1303
  raise SimEngineError("state and clemory cannot both be None in _load_bytes().")
@@ -1306,7 +1319,7 @@ class PcodeLifterEngineMixin(SimEngineBase):
1306
1319
 
1307
1320
  # Load from the clemory if we can
1308
1321
  if not load_from_state or not state:
1309
- if isinstance(clemory, cle.Clemory):
1322
+ if isinstance(clemory, (cle.Clemory, cle.ClemoryReadOnlyView)):
1310
1323
  try:
1311
1324
  start, backer = next(clemory.backers(addr))
1312
1325
  except StopIteration:
@@ -39,10 +39,8 @@ l = logging.getLogger("angr.engines.soot.expressions")
39
39
 
40
40
  def translate_expr(expr, state):
41
41
  expr_name = expr.__class__.__name__.split(".")[-1]
42
- if expr_name.startswith("Soot"):
43
- expr_name = expr_name[4:]
44
- if expr_name.endswith("Expr"):
45
- expr_name = expr_name[:-4]
42
+ expr_name = expr_name.removeprefix("Soot")
43
+ expr_name = expr_name.removesuffix("Expr")
46
44
  expr_cls_name = "SimSootExpr_" + expr_name
47
45
 
48
46
  g = globals()
@@ -16,8 +16,7 @@ l = logging.getLogger("angr.engines.soot.statements")
16
16
 
17
17
  def translate_stmt(stmt, state):
18
18
  stmt_name = stmt.__class__.__name__.split(".")[-1]
19
- if stmt_name.endswith("Stmt"):
20
- stmt_name = stmt_name[:-4]
19
+ stmt_name = stmt_name.removesuffix("Stmt")
21
20
 
22
21
  stmt_cls_name = f"SimSootStmt_{stmt_name}"
23
22
  if stmt_cls_name in globals():
@@ -12,8 +12,7 @@ from .strref import SimSootValue_StringRef
12
12
 
13
13
  def translate_value(value, state):
14
14
  value_name = value.__class__.__name__
15
- if value_name.startswith("Soot"):
16
- value_name = value_name[4:]
15
+ value_name = value_name.removeprefix("Soot")
17
16
  value_cls_name = "SimSootValue_" + value_name
18
17
 
19
18
  g = globals()
@@ -269,11 +269,11 @@ class SimSuccessors:
269
269
  # categorize the state
270
270
  if o.APPROXIMATE_GUARDS in state.options and state.solver.is_false(state.scratch.guard, exact=False):
271
271
  if o.VALIDATE_APPROXIMATIONS in state.options and state.satisfiable():
272
- raise Exception("WTF")
272
+ raise AssertionError("WTF")
273
273
  self.unsat_successors.append(state)
274
274
  elif o.APPROXIMATE_SATISFIABILITY in state.options and not state.solver.satisfiable(exact=False):
275
275
  if o.VALIDATE_APPROXIMATIONS in state.options and state.solver.satisfiable():
276
- raise Exception("WTF")
276
+ raise AssertionError("WTF")
277
277
  self.unsat_successors.append(state)
278
278
  elif (not state.scratch.guard.symbolic and state.solver.is_false(state.scratch.guard)) or (
279
279
  o.LAZY_SOLVES not in state.options and not state.satisfiable()
@@ -295,10 +295,15 @@ class SimSuccessors:
295
295
  # syscall
296
296
  self.successors.append(state)
297
297
 
298
- # Misuse the ip_at_syscall register to save the return address for this syscall
299
- # state.ip *might be* changed to be the real address of syscall SimProcedures by syscall handling code in
300
- # angr
301
- state.regs.ip_at_syscall = state.ip
298
+ if "ip_at_syscall" in state.arch.registers:
299
+ # Misuse the ip_at_syscall register to save the return address for this syscall
300
+ # state.ip *might be* changed to be the real address
301
+ # of syscall SimProcedures by syscall handling code in angr
302
+ state.regs.ip_at_syscall = state.ip
303
+ else:
304
+ # The architecture doesn't have an ip_at_syscall register.
305
+ # Nothing to do but hope vigorously.
306
+ l.warning(f"Handling syscall on arch {state.arch.name:s} without ip_at_syscall register")
302
307
 
303
308
  try:
304
309
  symbolic_syscall_num, concrete_syscall_nums = self._resolve_syscall(state)
@@ -57,7 +57,7 @@ class VEXLifter(SimEngineBase):
57
57
  self.selfmodifying_code = False
58
58
 
59
59
  # block cache
60
- self._block_cache = None
60
+ self._block_cache: LRUCache = None
61
61
  self._block_cache_hits = 0
62
62
  self._block_cache_misses = 0
63
63
 
@@ -78,8 +78,8 @@ class VEXLifter(SimEngineBase):
78
78
  self,
79
79
  addr=None,
80
80
  state=None,
81
- clemory=None,
82
- insn_bytes=None,
81
+ clemory: cle.Clemory | cle.ClemoryReadOnlyView | None = None,
82
+ insn_bytes: bytes | None = None,
83
83
  offset=None,
84
84
  arch=None,
85
85
  size=None,
@@ -94,7 +94,7 @@ class VEXLifter(SimEngineBase):
94
94
  cross_insn_opt=None,
95
95
  load_from_ro_regions=False,
96
96
  const_prop=False,
97
- ):
97
+ ) -> pyvex.IRSB:
98
98
  """
99
99
  Lift an IRSB.
100
100
 
@@ -245,6 +245,7 @@ class VEXLifter(SimEngineBase):
245
245
  raise SimEngineError(f"No bytes in memory for block starting at {addr:#x}.")
246
246
 
247
247
  # phase 5: call into pyvex
248
+ buff: bytes | claripy.ast.BV
248
249
  l.debug("Creating IRSB of %s at %#x", arch, addr)
249
250
  try:
250
251
  for subphase in range(2):
@@ -287,7 +288,9 @@ class VEXLifter(SimEngineBase):
287
288
  l.debug("Using bytes: %r", pyvex.ffi.buffer(buff, size))
288
289
  raise SimTranslationError("Unable to translate bytecode") from e
289
290
 
290
- def _load_bytes(self, addr, max_size, state=None, clemory=None):
291
+ def _load_bytes(
292
+ self, addr, max_size, state=None, clemory: cle.Clemory | cle.ClemoryReadOnlyView | None = None
293
+ ) -> tuple[bytes, int, int]:
291
294
  if clemory is None and state is None:
292
295
  raise SimEngineError("state and clemory cannot both be None in _load_bytes().")
293
296
 
@@ -308,7 +311,7 @@ class VEXLifter(SimEngineBase):
308
311
 
309
312
  # Load from the clemory if we can
310
313
  if not load_from_state or not state:
311
- if isinstance(clemory, cle.Clemory):
314
+ if isinstance(clemory, (cle.Clemory, cle.ClemoryReadOnlyView)):
312
315
  try:
313
316
  start, backer = next(clemory.backers(addr))
314
317
  except StopIteration:
angr/flirt/build_sig.py CHANGED
@@ -22,9 +22,7 @@ def get_basic_info(ar_path: str) -> dict[str, str]:
22
22
  """
23
23
 
24
24
  with tempfile.TemporaryDirectory() as tempdirname:
25
- cwd = os.getcwd()
26
- os.chdir(tempdirname)
27
- subprocess.call(["ar", "x", ar_path])
25
+ subprocess.call(["ar", "x", ar_path], cwd=tempdirname)
28
26
 
29
27
  # Load arch and OS information from the first .o file
30
28
  o_files = [f for f in os.listdir(".") if f.endswith(".o")]
@@ -32,8 +30,8 @@ def get_basic_info(ar_path: str) -> dict[str, str]:
32
30
  proj = angr.Project(o_files[0], auto_load_libs=False)
33
31
  arch_name = proj.arch.name.lower()
34
32
  os_name = proj.simos.name.lower()
35
-
36
- os.chdir(cwd)
33
+ else:
34
+ raise ValueError("No .o files found in the archive.")
37
35
 
38
36
  return {
39
37
  "arch": arch_name,
@@ -64,9 +62,7 @@ def get_unique_strings(ar_path: str) -> list[str]:
64
62
  # extract the archive file into a temporary directory
65
63
  all_strings = set()
66
64
  with tempfile.TemporaryDirectory() as tempdirname:
67
- cwd = os.getcwd()
68
- os.chdir(tempdirname)
69
- subprocess.call(["ar", "x", ar_path])
65
+ subprocess.call(["ar", "x", ar_path], cwd=tempdirname)
70
66
 
71
67
  for filename in os.listdir("."):
72
68
  if filename.endswith(".o"):
@@ -93,8 +89,6 @@ def get_unique_strings(ar_path: str) -> list[str]:
93
89
  non_symbol_strings.add(s)
94
90
  all_strings |= non_symbol_strings
95
91
 
96
- os.chdir(cwd)
97
-
98
92
  grouped_strings = defaultdict(set)
99
93
  for s in all_strings:
100
94
  grouped_strings[s[:5]].add(s)
@@ -138,7 +132,7 @@ def process_exc_file(exc_path: str):
138
132
 
139
133
  TODO: Add caller-callee-based de-duplication.
140
134
  """
141
- with open(exc_path) as f:
135
+ with open(exc_path, encoding="utf-8") as f:
142
136
  data = f.read()
143
137
  lines = data.split("\n")
144
138
 
@@ -184,7 +178,7 @@ def process_exc_file(exc_path: str):
184
178
  g[the_chosen_one] = "+" + line
185
179
 
186
180
  # output
187
- with open(exc_path, "w") as f:
181
+ with open(exc_path, "w", encoding="utf-8") as f:
188
182
  for g in groups.values():
189
183
  for line in g.values():
190
184
  f.write(line + "\n")
@@ -273,8 +267,7 @@ def main():
273
267
  basename = os.path.basename(ar_path)
274
268
 
275
269
  # sanitize basename since otherwise sigmake is not happy with it
276
- if basename.endswith(".a"):
277
- basename = basename[:-2]
270
+ basename = basename.removesuffix(".a")
278
271
  basename = basename.replace("+", "plus")
279
272
 
280
273
  # sanitize signame as well
@@ -292,7 +285,7 @@ def main():
292
285
 
293
286
  assert not has_collision
294
287
 
295
- with open(meta_path, "w") as f:
288
+ with open(meta_path, "w", encoding="utf-8") as f:
296
289
  metadata = {
297
290
  "unique_strings": unique_strings,
298
291
  }
@@ -70,13 +70,10 @@ class Function(Serializable):
70
70
  "is_simprocedure",
71
71
  "is_syscall",
72
72
  "normalized",
73
- "prepared_registers",
74
- "prepared_stack_variables",
75
73
  "previous_names",
76
74
  "prototype",
77
75
  "prototype_libname",
78
76
  "ran_cca",
79
- "registers_read_afterwards",
80
77
  "retaddr_on_stack",
81
78
  "sp_delta",
82
79
  "startpoint",
@@ -149,9 +146,6 @@ class Function(Serializable):
149
146
  self.is_prototype_guessed: bool = True
150
147
  # Whether this function returns or not. `None` means it's not determined yet
151
148
  self._returning = None
152
- self.prepared_registers = set()
153
- self.prepared_stack_variables = set()
154
- self.registers_read_afterwards = set()
155
149
 
156
150
  self._addr_to_block_node = {} # map addresses to nodes. it's a cache of blocks. if a block is removed from the
157
151
  # function, it may not be removed from _addr_to_block_node. if you want to list
@@ -1,7 +1,11 @@
1
+ # pylint:disable=super-init-not-called
1
2
  from __future__ import annotations
2
3
  import os
3
- import networkx
4
4
  from collections import defaultdict
5
+
6
+ import networkx
7
+
8
+ from angr.codenode import BlockNode
5
9
  from .function import Function
6
10
 
7
11
 
@@ -88,10 +92,6 @@ class SootFunction(Function):
88
92
  if hooker and hasattr(hooker, "NO_RET"):
89
93
  self.returning = not hooker.NO_RET
90
94
 
91
- self.prepared_registers = set()
92
- self.prepared_stack_variables = set()
93
- self.registers_read_afterwards = set()
94
-
95
95
  # startpoint can always be None if this CFGNode is a syscall node
96
96
  self.startpoint = None
97
97
 
@@ -126,6 +126,3 @@ class SootFunction(Function):
126
126
  if isinstance(node, BlockNode) and node.addr not in self._addr_to_block_node:
127
127
  self._addr_to_block_node[node.addr] = node
128
128
  return node
129
-
130
-
131
- from angr.codenode import BlockNode
@@ -915,7 +915,7 @@ class VariableManagerInternal(Serializable):
915
915
  # rename variables in a fixed order
916
916
  var_ctr = count(0)
917
917
 
918
- sorted_stack_variables = sorted(sorted_stack_variables, key=lambda v: v.offset)
918
+ sorted_stack_variables = sorted(sorted_stack_variables, key=lambda v: (v.offset, v.ident))
919
919
  sorted_reg_variables = sorted(sorted_reg_variables, key=lambda v: _id_from_varident(v.ident))
920
920
 
921
921
  # find variables that are likely only used by phi assignments
@@ -1033,7 +1033,7 @@ class VariableManagerInternal(Serializable):
1033
1033
  Map SSA variables to a unified variable. Fill in self._unified_variables.
1034
1034
  """
1035
1035
 
1036
- stack_vars: dict[int, list[SimStackVariable]] = defaultdict(list)
1036
+ stack_vars: set[SimStackVariable] = set()
1037
1037
  reg_vars: set[SimRegisterVariable] = set()
1038
1038
 
1039
1039
  # unify stack variables based on their locations
@@ -1042,19 +1042,14 @@ class VariableManagerInternal(Serializable):
1042
1042
  # do not unify twice
1043
1043
  continue
1044
1044
  if isinstance(v, SimStackVariable):
1045
- stack_vars[v.offset].append(v)
1045
+ stack_vars.add(v)
1046
1046
  elif isinstance(v, SimRegisterVariable):
1047
1047
  reg_vars.add(v)
1048
1048
 
1049
- for _, vs in stack_vars.items():
1050
- unified = vs[0].copy()
1051
- for v in vs:
1052
- self.set_unified_variable(v, unified)
1053
-
1054
1049
  # unify register variables based on phi nodes
1055
1050
  graph = networkx.DiGraph() # an edge v1 -> v2 means v2 is the phi variable for v1
1056
1051
  for v, subvs in self._phi_variables.items():
1057
- if not isinstance(v, SimRegisterVariable):
1052
+ if not isinstance(v, (SimRegisterVariable, SimStackVariable)):
1058
1053
  continue
1059
1054
  for subv in subvs:
1060
1055
  graph.add_edge(subv, v)
@@ -1086,10 +1081,21 @@ class VariableManagerInternal(Serializable):
1086
1081
  self.set_unified_variable(v, unified)
1087
1082
  for v in nodes:
1088
1083
  reg_vars.discard(v)
1084
+ stack_vars.discard(v)
1089
1085
 
1090
- for v in reg_vars:
1086
+ # deal with remaining variables
1087
+ for v in sorted(reg_vars, key=lambda v: v.ident):
1091
1088
  self.set_unified_variable(v, v)
1092
1089
 
1090
+ stack_vars_by_offset: dict[int, list[SimStackVariable]] = defaultdict(list)
1091
+ for v in stack_vars:
1092
+ stack_vars_by_offset[v.offset].append(v)
1093
+ for vs in stack_vars_by_offset.values():
1094
+ vs = sorted(vs, key=lambda v: v.ident)
1095
+ unified = vs[0].copy()
1096
+ for v in vs:
1097
+ self.set_unified_variable(v, unified)
1098
+
1093
1099
  def set_unified_variable(self, variable: SimVariable, unified: SimVariable) -> None:
1094
1100
  """
1095
1101
  Set the unified variable for a given SSA variable.
angr/lib/angr_native.dll CHANGED
Binary file
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: angr
3
- Version: 9.2.136
3
+ Version: 9.2.137
4
4
  Summary: A multi-architecture binary analysis toolkit, with the ability to perform dynamic symbolic execution and various static analyses on binaries
5
5
  Home-page: https://github.com/angr/angr
6
6
  License: BSD-2-Clause
@@ -16,13 +16,13 @@ Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
17
  Requires-Dist: CppHeaderParser
18
18
  Requires-Dist: GitPython
19
- Requires-Dist: ailment==9.2.136
20
- Requires-Dist: archinfo==9.2.136
19
+ Requires-Dist: ailment==9.2.137
20
+ Requires-Dist: archinfo==9.2.137
21
21
  Requires-Dist: cachetools
22
22
  Requires-Dist: capstone==5.0.3
23
23
  Requires-Dist: cffi>=1.14.0
24
- Requires-Dist: claripy==9.2.136
25
- Requires-Dist: cle==9.2.136
24
+ Requires-Dist: claripy==9.2.137
25
+ Requires-Dist: cle==9.2.137
26
26
  Requires-Dist: itanium-demangler
27
27
  Requires-Dist: mulpyplexer
28
28
  Requires-Dist: nampa
@@ -31,7 +31,7 @@ Requires-Dist: protobuf>=5.28.2
31
31
  Requires-Dist: psutil
32
32
  Requires-Dist: pycparser>=2.18
33
33
  Requires-Dist: pyformlang
34
- Requires-Dist: pyvex==9.2.136
34
+ Requires-Dist: pyvex==9.2.137
35
35
  Requires-Dist: rich>=13.1.0
36
36
  Requires-Dist: sortedcontainers
37
37
  Requires-Dist: sympy