angr 9.2.136__py3-none-macosx_11_0_arm64.whl → 9.2.138__py3-none-macosx_11_0_arm64.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 (65) 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 +31 -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 +6 -3
  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/decompilation_options.py +10 -0
  18. angr/analyses/decompiler/decompiler.py +1 -0
  19. angr/analyses/decompiler/dephication/dephication_base.py +2 -0
  20. angr/analyses/decompiler/dephication/rewriting_engine.py +8 -6
  21. angr/analyses/decompiler/dephication/seqnode_dephication.py +10 -1
  22. angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +2 -2
  23. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +1 -2
  24. angr/analyses/decompiler/peephole_optimizations/remove_redundant_nots.py +21 -3
  25. angr/analyses/decompiler/sequence_walker.py +6 -2
  26. angr/analyses/decompiler/ssailification/rewriting.py +11 -1
  27. angr/analyses/decompiler/ssailification/rewriting_engine.py +56 -19
  28. angr/analyses/decompiler/ssailification/ssailification.py +13 -3
  29. angr/analyses/decompiler/ssailification/traversal.py +28 -2
  30. angr/analyses/decompiler/ssailification/traversal_state.py +6 -1
  31. angr/analyses/decompiler/structured_codegen/c.py +44 -21
  32. angr/analyses/decompiler/structuring/phoenix.py +117 -14
  33. angr/analyses/decompiler/utils.py +113 -8
  34. angr/analyses/reaching_definitions/function_handler.py +1 -1
  35. angr/analyses/s_liveness.py +5 -1
  36. angr/analyses/s_propagator.py +127 -28
  37. angr/analyses/s_reaching_definitions/s_rda_model.py +2 -1
  38. angr/analyses/s_reaching_definitions/s_rda_view.py +20 -1
  39. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +11 -1
  40. angr/analyses/stack_pointer_tracker.py +26 -16
  41. angr/analyses/variable_recovery/engine_ail.py +19 -7
  42. angr/analyses/variable_recovery/engine_base.py +16 -14
  43. angr/analyses/variable_recovery/engine_vex.py +2 -2
  44. angr/analyses/variable_recovery/variable_recovery_fast.py +22 -1
  45. angr/block.py +59 -20
  46. angr/engines/pcode/emulate.py +1 -1
  47. angr/engines/pcode/lifter.py +31 -18
  48. angr/engines/soot/expressions/__init__.py +2 -4
  49. angr/engines/soot/statements/__init__.py +1 -2
  50. angr/engines/soot/values/__init__.py +1 -2
  51. angr/engines/successors.py +11 -6
  52. angr/engines/vex/lifter.py +9 -6
  53. angr/flirt/build_sig.py +8 -15
  54. angr/knowledge_plugins/functions/function.py +0 -6
  55. angr/knowledge_plugins/functions/soot_function.py +5 -8
  56. angr/knowledge_plugins/variables/variable_manager.py +16 -10
  57. angr/lib/angr_native.dylib +0 -0
  58. angr/procedures/glibc/__libc_start_main.py +10 -3
  59. angr/utils/ssa/__init__.py +14 -1
  60. {angr-9.2.136.dist-info → angr-9.2.138.dist-info}/METADATA +7 -7
  61. {angr-9.2.136.dist-info → angr-9.2.138.dist-info}/RECORD +65 -64
  62. {angr-9.2.136.dist-info → angr-9.2.138.dist-info}/WHEEL +1 -1
  63. {angr-9.2.136.dist-info → angr-9.2.138.dist-info}/LICENSE +0 -0
  64. {angr-9.2.136.dist-info → angr-9.2.138.dist-info}/entry_points.txt +0 -0
  65. {angr-9.2.136.dist-info → angr-9.2.138.dist-info}/top_level.txt +0 -0
angr/block.py CHANGED
@@ -1,10 +1,11 @@
1
1
  # pylint:disable=wrong-import-position,arguments-differ
2
2
  from __future__ import annotations
3
3
  import logging
4
+ from typing import TYPE_CHECKING
4
5
 
5
6
  import pyvex
6
7
  from pyvex import IRSB
7
- from archinfo import ArchARM
8
+ from archinfo import Arch, ArchARM
8
9
 
9
10
  from .protos import primitives_pb2 as pb2
10
11
  from .serializable import Serializable
@@ -14,6 +15,12 @@ try:
14
15
  except ImportError:
15
16
  pcode = None
16
17
 
18
+ if TYPE_CHECKING:
19
+ from angr import Project
20
+ from angr.engines.vex import VEXLifter
21
+ from angr.engines.pcode.lifter import PcodeLifterEngineMixin, IRSB as PcodeIRSB
22
+ from angr.engines.soot.engine import SootMixin
23
+
17
24
 
18
25
  l = logging.getLogger(name=__name__)
19
26
 
@@ -148,7 +155,7 @@ class Block(Serializable):
148
155
  self,
149
156
  addr,
150
157
  project=None,
151
- arch=None,
158
+ arch: Arch = None,
152
159
  size=None,
153
160
  max_size=None,
154
161
  byte_string=None,
@@ -168,6 +175,7 @@ class Block(Serializable):
168
175
  skip_stmts=False,
169
176
  ):
170
177
  # set up arch
178
+ self.arch: Arch
171
179
  if project is not None:
172
180
  self.arch = project.arch
173
181
  else:
@@ -187,7 +195,7 @@ class Block(Serializable):
187
195
  else:
188
196
  thumb = False
189
197
 
190
- self._project = project
198
+ self._project: Project | None = project
191
199
  self.thumb = thumb
192
200
  self.addr = addr
193
201
  self._opt_level = opt_level
@@ -206,8 +214,15 @@ class Block(Serializable):
206
214
  else:
207
215
  if self._initial_regs:
208
216
  self.set_initial_regs()
217
+ clemory = None
218
+ if project is not None:
219
+ clemory = (
220
+ project.loader.memory_ro_view
221
+ if project.loader.memory_ro_view is not None
222
+ else project.loader.memory
223
+ )
209
224
  vex = self._vex_engine.lift_vex(
210
- clemory=project.loader.memory,
225
+ clemory=clemory,
211
226
  state=backup_state,
212
227
  insn_bytes=byte_string,
213
228
  addr=addr,
@@ -243,7 +258,7 @@ class Block(Serializable):
243
258
  self._load_from_ro_regions = load_from_ro_regions
244
259
  self._const_prop = const_prop
245
260
 
246
- self._instructions = num_inst
261
+ self._instructions: int | None = num_inst
247
262
  self._instruction_addrs: list[int] = []
248
263
 
249
264
  if skip_stmts:
@@ -258,7 +273,7 @@ class Block(Serializable):
258
273
  if type(self._bytes) is memoryview:
259
274
  self._bytes = bytes(self._bytes)
260
275
  elif type(self._bytes) is not bytes:
261
- self._bytes = bytes(pyvex.ffi.buffer(self._bytes, size))
276
+ self._bytes = bytes(pyvex.ffi.buffer(self._bytes, size)) # type:ignore
262
277
  else:
263
278
  self._bytes = None
264
279
  elif type(byte_string) is bytes:
@@ -269,7 +284,7 @@ class Block(Serializable):
269
284
  else:
270
285
  # Convert bytestring to a str
271
286
  # size will ALWAYS be known at this point
272
- self._bytes = str(pyvex.ffi.buffer(byte_string, self.size))
287
+ self._bytes = bytes(pyvex.ffi.buffer(byte_string, self.size)) # type:ignore
273
288
 
274
289
  def _parse_vex_info(self, vex_block):
275
290
  if vex_block is not None:
@@ -323,16 +338,25 @@ class Block(Serializable):
323
338
  pyvex.pvc.reset_initial_register_values()
324
339
 
325
340
  @property
326
- def _vex_engine(self):
327
- return self._project.factory.default_engine
341
+ def _vex_engine(self) -> VEXLifter | PcodeLifterEngineMixin:
342
+ if self._project is None:
343
+ raise ValueError("Project is not set")
344
+ return self._project.factory.default_engine # type:ignore
328
345
 
329
346
  @property
330
- def vex(self) -> IRSB:
347
+ def vex(self) -> IRSB | PcodeIRSB:
331
348
  if not self._vex:
332
349
  if self._initial_regs:
333
350
  self.set_initial_regs()
351
+ clemory = None
352
+ if self._project is not None:
353
+ clemory = (
354
+ self._project.loader.memory_ro_view
355
+ if self._project.loader.memory_ro_view is not None
356
+ else self._project.loader.memory
357
+ )
334
358
  self._vex = self._vex_engine.lift_vex(
335
- clemory=self._project.loader.memory if self._project is not None else None,
359
+ clemory=clemory,
336
360
  insn_bytes=self._bytes,
337
361
  addr=self.addr,
338
362
  thumb=self.thumb,
@@ -350,6 +374,7 @@ class Block(Serializable):
350
374
  self.reset_initial_regs()
351
375
  self._parse_vex_info(self._vex)
352
376
 
377
+ assert self._vex is not None
353
378
  return self._vex
354
379
 
355
380
  @property
@@ -362,8 +387,15 @@ class Block(Serializable):
362
387
 
363
388
  if self._initial_regs:
364
389
  self.set_initial_regs()
390
+ clemory = None
391
+ if self._project is not None:
392
+ clemory = (
393
+ self._project.loader.memory_ro_view
394
+ if self._project.loader.memory_ro_view is not None
395
+ else self._project.loader.memory
396
+ )
365
397
  self._vex_nostmt = self._vex_engine.lift_vex(
366
- clemory=self._project.loader.memory if self._project is not None else None,
398
+ clemory=clemory,
367
399
  insn_bytes=self._bytes,
368
400
  addr=self.addr,
369
401
  thumb=self.thumb,
@@ -394,17 +426,17 @@ class Block(Serializable):
394
426
  """
395
427
  if self._disassembly is None:
396
428
  if self._using_pcode_engine:
397
- self._disassembly = self.vex.disassembly
429
+ self._disassembly = self.vex.disassembly # type:ignore
398
430
  else:
399
431
  self._disassembly = self.capstone
400
432
  return self._disassembly
401
433
 
402
434
  @property
403
- def capstone(self):
435
+ def capstone(self) -> CapstoneBlock:
404
436
  if self._capstone:
405
437
  return self._capstone
406
438
 
407
- cs = self.arch.capstone if not self.thumb else self.arch.capstone_thumb
439
+ cs = self.arch.capstone if not self.thumb else self.arch.capstone_thumb # type:ignore
408
440
 
409
441
  insns = []
410
442
 
@@ -423,12 +455,18 @@ class Block(Serializable):
423
455
  return BlockNode(self.addr, self.size, bytestr=self.bytes, thumb=self.thumb)
424
456
 
425
457
  @property
426
- def bytes(self) -> bytes:
458
+ def bytes(self) -> bytes | None:
427
459
  if self._bytes is None:
428
460
  addr = self.addr
429
461
  if self.thumb:
430
462
  addr = (addr >> 1) << 1
431
- self._bytes = self._project.loader.memory.load(addr, self.size)
463
+ if self._project is not None:
464
+ mem = (
465
+ self._project.loader.memory_ro_view
466
+ if self._project.loader.memory_ro_view is not None
467
+ else self._project.loader.memory
468
+ )
469
+ self._bytes = mem.load(addr, self.size)
432
470
  return self._bytes
433
471
 
434
472
  @property
@@ -437,6 +475,7 @@ class Block(Serializable):
437
475
  # initialize from VEX
438
476
  _ = self.vex
439
477
 
478
+ assert self._instructions is not None
440
479
  return self._instructions
441
480
 
442
481
  @property
@@ -477,17 +516,17 @@ class SootBlock:
477
516
  Represents a Soot IR basic block.
478
517
  """
479
518
 
480
- def __init__(self, addr, project=None, arch=None):
519
+ def __init__(self, addr, *, project: Project, arch: Arch):
481
520
  self.addr = addr
482
521
  self.arch = arch
483
522
  self._project = project
484
523
  self._the_binary = project.loader.main_object
485
524
 
486
525
  @property
487
- def _soot_engine(self):
526
+ def _soot_engine(self) -> SootMixin:
488
527
  if self._project is None:
489
528
  assert False, "This should be unreachable"
490
- return self._project.factory.default_engine
529
+ return self._project.factory.default_engine # type:ignore
491
530
 
492
531
  @property
493
532
  def soot(self):
@@ -92,7 +92,7 @@ class PcodeEmulatorMixin(SimEngineBase):
92
92
  self.state,
93
93
  fallthru_addr,
94
94
  self.state.scratch.guard,
95
- "Ijk_Boring",
95
+ irsb.jumpkind,
96
96
  exit_stmt_idx=DEFAULT_STATEMENT,
97
97
  exit_ins_addr=self.state.scratch.ins_addr,
98
98
  )
@@ -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