angr 9.2.76__py3-none-win_amd64.whl → 9.2.77__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 (37) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/indirect_jump_resolvers/amd64_pe_iat.py +7 -1
  3. angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +7 -1
  4. angr/analyses/decompiler/clinic.py +4 -1
  5. angr/analyses/decompiler/condition_processor.py +4 -0
  6. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +4 -3
  7. angr/analyses/decompiler/optimization_passes/multi_simplifier.py +1 -1
  8. angr/analyses/decompiler/structured_codegen/c.py +3 -0
  9. angr/analyses/propagator/engine_ail.py +1 -1
  10. angr/analyses/reaching_definitions/engine_ail.py +3 -6
  11. angr/analyses/reaching_definitions/engine_vex.py +32 -2
  12. angr/analyses/reaching_definitions/function_handler.py +1 -1
  13. angr/analyses/reaching_definitions/rd_initializer.py +6 -6
  14. angr/analyses/reaching_definitions/rd_state.py +9 -11
  15. angr/analyses/typehoon/typevars.py +19 -29
  16. angr/analyses/variable_recovery/variable_recovery_fast.py +33 -31
  17. angr/engines/light/engine.py +1 -1
  18. angr/keyed_region.py +19 -3
  19. angr/knowledge_plugins/functions/function.py +8 -0
  20. angr/knowledge_plugins/key_definitions/live_definitions.py +53 -44
  21. angr/knowledge_plugins/key_definitions/liveness.py +102 -34
  22. angr/knowledge_plugins/key_definitions/rd_model.py +4 -4
  23. angr/knowledge_plugins/propagations/states.py +3 -1
  24. angr/knowledge_plugins/variables/variable_manager.py +51 -25
  25. angr/lib/angr_native.dll +0 -0
  26. angr/misc/bug_report.py +2 -2
  27. angr/storage/memory_mixins/__init__.py +3 -2
  28. angr/storage/memory_mixins/paged_memory/paged_memory_multivalue_mixin.py +63 -0
  29. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +5 -0
  30. {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/METADATA +6 -6
  31. {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/RECORD +37 -36
  32. tests/analyses/decompiler/test_decompiler.py +5 -1
  33. tests/analyses/test_flirt.py +3 -1
  34. tests/procedures/libc/test_string.py +2 -1
  35. {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/LICENSE +0 -0
  36. {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/WHEEL +0 -0
  37. {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/top_level.txt +0 -0
angr/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # pylint: disable=wildcard-import
2
2
  # pylint: disable=wrong-import-position
3
3
 
4
- __version__ = "9.2.76"
4
+ __version__ = "9.2.77"
5
5
 
6
6
  if bytes is str:
7
7
  raise Exception(
@@ -22,7 +22,13 @@ class AMD64PeIatResolver(IndirectJumpResolver):
22
22
  if jumpkind not in {"Ijk_Call", "Ijk_Boring"}:
23
23
  return False
24
24
 
25
- opnd = self.project.factory.block(addr).capstone.insns[-1].insn.operands[0]
25
+ insns = self.project.factory.block(addr).capstone.insns
26
+ if not insns:
27
+ return False
28
+ if not insns[-1].insn.operands:
29
+ return False
30
+
31
+ opnd = insns[-1].insn.operands[0]
26
32
  # Must be of the form: call qword ptr [0xABCD]
27
33
  if opnd.type == X86_OP_MEM and opnd.mem.disp and opnd.mem.base == X86_REG_RIP and opnd.mem.index == 0:
28
34
  return True
@@ -22,7 +22,13 @@ class X86PeIatResolver(IndirectJumpResolver):
22
22
  if jumpkind != "Ijk_Call":
23
23
  return False
24
24
 
25
- opnd = self.project.factory.block(addr).capstone.insns[-1].insn.operands[0]
25
+ insns = self.project.factory.block(addr).capstone.insns
26
+ if not insns:
27
+ return False
28
+ if not insns[-1].insn.operands:
29
+ return False
30
+
31
+ opnd = insns[-1].insn.operands[0]
26
32
  # Must be of the form: call ds:0xABCD
27
33
  if opnd.type == X86_OP_MEM and opnd.mem.disp and not opnd.mem.base and not opnd.mem.index:
28
34
  return True
@@ -1399,7 +1399,10 @@ class Clinic(Analysis):
1399
1399
  )
1400
1400
  end_block_ail = ailment.IRSBConverter.convert(end_block.vex, self._ail_manager)
1401
1401
  else:
1402
- end_block_ail = next(iter(b for b in ail_graph if b.addr == end_block_addr))
1402
+ try:
1403
+ end_block_ail = next(iter(b for b in ail_graph if b.addr == end_block_addr))
1404
+ except StopIteration:
1405
+ return None
1403
1406
 
1404
1407
  # last check: if the first instruction of the end block has Sar, then we bail (due to the peephole optimization
1405
1408
  # SarToSignedDiv)
@@ -102,6 +102,7 @@ _ail2claripy_op_mapping = {
102
102
  "Shr": lambda expr, conv, _: _op_with_unified_size(claripy.LShR, conv, expr.operands[0], expr.operands[1]),
103
103
  "Shl": lambda expr, conv, _: _op_with_unified_size(operator.lshift, conv, expr.operands[0], expr.operands[1]),
104
104
  "Sar": lambda expr, conv, _: _op_with_unified_size(operator.rshift, conv, expr.operands[0], expr.operands[1]),
105
+ "Concat": lambda expr, conv, _: claripy.Concat(*[conv(operand) for operand in expr.operands]),
105
106
  # There are no corresponding claripy operations for the following operations
106
107
  "DivMod": lambda expr, _, m: _dummy_bvs(expr, m),
107
108
  "CmpF": lambda expr, _, m: _dummy_bvs(expr, m),
@@ -686,6 +687,9 @@ class ConditionProcessor:
686
687
  if cond_.args[0] is True
687
688
  else ailment.Expr.Const(None, None, False, 1, **tags),
688
689
  "Extract": lambda cond_, tags: self._convert_extract(*cond_.args, tags, memo=memo),
690
+ "ZeroExt": lambda cond_, tags: _binary_op_reduce(
691
+ "Concat", [claripy.BVV(0, cond_.args[0]), cond_.args[1]], tags
692
+ ),
689
693
  }
690
694
 
691
695
  if cond.op in _mapping:
@@ -146,14 +146,15 @@ class ITERegionConverter(OptimizationPass):
146
146
  #
147
147
 
148
148
  new_region_head = region_head.copy()
149
+ addr_obj = true_stmt.src if "ins_addr" in true_stmt.src.tags else true_stmt
149
150
  ternary_expr = ITE(
150
151
  None,
151
152
  region_head.statements[-1].condition,
152
153
  true_stmt.src,
153
154
  false_stmt.src,
154
- ins_addr=true_stmt.src.ins_addr,
155
- vex_block_addr=true_stmt.src.vex_block_addr,
156
- vex_stmt_idx=true_stmt.src.vex_stmt_idx,
155
+ ins_addr=addr_obj.ins_addr,
156
+ vex_block_addr=addr_obj.vex_block_addr,
157
+ vex_stmt_idx=addr_obj.vex_stmt_idx,
157
158
  )
158
159
  new_assignment = true_stmt.copy()
159
160
  new_assignment.src = ternary_expr
@@ -21,7 +21,7 @@ class MultiSimplifierAILEngine(SimplifierAILEngine):
21
21
  if type(operand_0) in [Expr.Convert, Expr.Register]:
22
22
  if isinstance(operand_1, (Expr.Convert, Expr.Register)):
23
23
  if operand_0 == operand_1:
24
- count = Expr.Const(expr.idx, None, 2, 8)
24
+ count = Expr.Const(expr.idx, None, 2, operand_1.bits)
25
25
  return Expr.BinaryOp(expr.idx, "Mul", [operand_1, count], expr.signed, **expr.tags)
26
26
  # 2*x + x = 3*x
27
27
  if Expr.BinaryOp in [type(operand_0), type(operand_1)]:
@@ -2721,6 +2721,9 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2721
2721
  o_constant, o_terms = extract_terms(expr)
2722
2722
 
2723
2723
  def bail_out():
2724
+ if len(o_terms) == 0:
2725
+ # probably a plain integer, return as is
2726
+ return expr
2724
2727
  result = reduce(
2725
2728
  lambda a1, a2: CBinaryOp("Add", a1, a2, codegen=self),
2726
2729
  (
@@ -1204,7 +1204,7 @@ class SimEnginePropagatorAIL(
1204
1204
  o1_expr if o1_expr is not None else expr.operands[1],
1205
1205
  ],
1206
1206
  expr.signed,
1207
- bits=o0_expr.bits * 2,
1207
+ bits=expr.bits,
1208
1208
  floating_point=expr.floating_point,
1209
1209
  rounding_mode=expr.rounding_mode,
1210
1210
  **expr.tags,
@@ -118,9 +118,6 @@ class SimEngineRDAIL(
118
118
  def _process_Stmt(self, whitelist=None):
119
119
  super()._process_Stmt(whitelist=whitelist)
120
120
 
121
- if self.state.analysis:
122
- self.state.analysis.model.complete_loc()
123
-
124
121
  def _handle_Stmt(self, stmt):
125
122
  if self.state.analysis:
126
123
  self.state.analysis.stmt_observe(self.stmt_idx, stmt, self.block, self.state, OP_BEFORE)
@@ -801,7 +798,7 @@ class SimEngineRDAIL(
801
798
  elif expr0_v is None and expr1_v is not None:
802
799
  # each value in expr0 >> expr1_v
803
800
  if expr0.count() == 1 and 0 in expr0:
804
- if all(v.concrete for v in expr0[0]):
801
+ if all(v.concrete for v in expr0[0]) and expr1_v.concrete:
805
802
  vs = {
806
803
  (claripy.LShR(v, expr1_v.concrete_value) if v.concrete else self.state.top(bits))
807
804
  for v in expr0[0]
@@ -839,7 +836,7 @@ class SimEngineRDAIL(
839
836
  elif expr0_v is None and expr1_v is not None:
840
837
  # each value in expr0 >> expr1_v
841
838
  if expr0.count() == 1 and 0 in expr0:
842
- if all(v.concrete for v in expr0[0]):
839
+ if all(v.concrete for v in expr0[0]) and expr1_v.concrete:
843
840
  vs = {
844
841
  (claripy.LShR(v, expr1_v.concrete_value) if v.concrete else self.state.top(bits))
845
842
  for v in expr0[0]
@@ -877,7 +874,7 @@ class SimEngineRDAIL(
877
874
  elif expr0_v is None and expr1_v is not None:
878
875
  # each value in expr0 << expr1_v
879
876
  if expr0.count() == 1 and 0 in expr0:
880
- if all(v.concrete for v in expr0[0]):
877
+ if all(v.concrete for v in expr0[0]) and expr1_v.concrete:
881
878
  vs = {((v << expr1_v.concrete_value) if v.concrete else self.state.top(bits)) for v in expr0[0]}
882
879
  r = MultiValues(offset_to_values={0: vs})
883
880
  elif expr0_v is not None and expr1_v is None:
@@ -147,11 +147,11 @@ class SimEngineRDVEX(
147
147
  if self.state.is_heap_address(d):
148
148
  heap_offset = self.state.get_heap_offset(d)
149
149
  if heap_offset is not None:
150
- self.state.add_heap_use(heap_offset, 1, "Iend_BE")
150
+ self.state.add_heap_use(heap_offset, 1)
151
151
  elif self.state.is_stack_address(d):
152
152
  stack_offset = self.state.get_stack_offset(d)
153
153
  if stack_offset is not None:
154
- self.state.add_stack_use(stack_offset, 1, "Iend_BE")
154
+ self.state.add_stack_use(stack_offset, 1)
155
155
 
156
156
  if self.state.exit_observed and reg_offset == self.arch.sp_offset:
157
157
  return
@@ -989,6 +989,34 @@ class SimEngineRDVEX(
989
989
  return MultiValues(claripy.BVV(0, 1))
990
990
  return MultiValues(self.state.top(1))
991
991
 
992
+ def _handle_CmpGT(self, expr):
993
+ arg0, arg1 = expr.args
994
+ expr_0 = self._expr(arg0)
995
+ expr_1 = self._expr(arg1)
996
+
997
+ e0 = expr_0.one_value()
998
+ e1 = expr_1.one_value()
999
+ if e0 is not None and e1 is not None:
1000
+ if not e0.symbolic and not e1.symbolic:
1001
+ return MultiValues(claripy.BVV(1, 1) if e0.concrete_value > e1.concrete_value else claripy.BVV(0, 1))
1002
+ elif e0 is e1:
1003
+ return MultiValues(claripy.BVV(0, 1))
1004
+ return MultiValues(self.state.top(1))
1005
+
1006
+ def _handle_CmpGE(self, expr):
1007
+ arg0, arg1 = expr.args
1008
+ expr_0 = self._expr(arg0)
1009
+ expr_1 = self._expr(arg1)
1010
+
1011
+ e0 = expr_0.one_value()
1012
+ e1 = expr_1.one_value()
1013
+ if e0 is not None and e1 is not None:
1014
+ if not e0.symbolic and not e1.symbolic:
1015
+ return MultiValues(claripy.BVV(1, 1) if e0.concrete_value >= e1.concrete_value else claripy.BVV(0, 1))
1016
+ elif e0 is e1:
1017
+ return MultiValues(claripy.BVV(0, 1))
1018
+ return MultiValues(self.state.top(1))
1019
+
992
1020
  # ppc only
993
1021
  def _handle_CmpORD(self, expr):
994
1022
  arg0, arg1 = expr.args
@@ -1001,6 +1029,8 @@ class SimEngineRDVEX(
1001
1029
 
1002
1030
  if e0 is not None and e1 is not None:
1003
1031
  if not e0.symbolic and not e1.symbolic:
1032
+ e0 = e0.concrete_value
1033
+ e1 = e1.concrete_value
1004
1034
  if e0 < e1:
1005
1035
  return MultiValues(claripy.BVV(0x8, bits))
1006
1036
  elif e0 > e1:
@@ -409,7 +409,7 @@ class FunctionHandler:
409
409
  # translate all the dep atoms into dep defns
410
410
  for effect in data.effects:
411
411
  if effect.sources_defns is None and effect.sources:
412
- effect.sources_defns = set().union(*(set(state.get_definitions(atom)) for atom in effect.sources))
412
+ effect.sources_defns = set().union(*(state.get_definitions(atom) for atom in effect.sources))
413
413
  if not effect.sources_defns:
414
414
  effect.sources_defns = {Definition(atom, ExternalCodeLocation()) for atom in effect.sources}
415
415
  other_input_defns |= effect.sources_defns - all_args_defns
@@ -63,7 +63,7 @@ class RDAStateInitializer:
63
63
  self.initialize_architectural_state(state, func_addr, ex_loc, rtoc_value)
64
64
 
65
65
  if state.analysis is not None:
66
- state.analysis.model.complete_loc()
66
+ state.analysis.model.make_liveness_snapshot()
67
67
 
68
68
  def initialize_all_function_arguments(
69
69
  self,
@@ -147,7 +147,7 @@ class RDAStateInitializer:
147
147
  rtoc_def = Definition(rtoc_atom, ex_loc, tags={InitialValueTag()})
148
148
  state.all_definitions.add(rtoc_def)
149
149
  if state.analysis is not None:
150
- state.analysis.model.add_def(rtoc_def, ex_loc)
150
+ state.analysis.model.add_def(rtoc_def)
151
151
  rtoc = state.annotate_with_def(claripy.BVV(rtoc_value, self.arch.bits), rtoc_def)
152
152
  state.registers.store(offset, rtoc)
153
153
  elif self.arch.name.startswith("MIPS64"):
@@ -156,7 +156,7 @@ class RDAStateInitializer:
156
156
  t9_def = Definition(t9_atom, ex_loc, tags={InitialValueTag()})
157
157
  state.all_definitions.add(t9_def)
158
158
  if state.analysis is not None:
159
- state.analysis.model.add_def(t9_def, ex_loc)
159
+ state.analysis.model.add_def(t9_def)
160
160
  t9 = state.annotate_with_def(claripy.BVV(func_addr, self.arch.bits), t9_def)
161
161
  state.registers.store(offset, t9)
162
162
  elif self.arch.name.startswith("MIPS"):
@@ -167,7 +167,7 @@ class RDAStateInitializer:
167
167
  t9_def = Definition(t9_atom, ex_loc, tags={InitialValueTag()})
168
168
  state.all_definitions.add(t9_def)
169
169
  if state.analysis is not None:
170
- state.analysis.model.add_def(t9_def, ex_loc)
170
+ state.analysis.model.add_def(t9_def)
171
171
  t9 = state.annotate_with_def(claripy.BVV(func_addr, self.arch.bits), t9_def)
172
172
  state.registers.store(t9_offset, t9)
173
173
 
@@ -185,7 +185,7 @@ class RDAStateInitializer:
185
185
  reg_def = Definition(reg_atom, ex_loc, tags={ParameterTag(function=func_addr)})
186
186
  state.all_definitions.add(reg_def)
187
187
  if state.analysis is not None:
188
- state.analysis.model.add_def(reg_def, ex_loc)
188
+ state.analysis.model.add_def(reg_def)
189
189
  if value is None:
190
190
  value = state.top(self.arch.bits)
191
191
  reg = state.annotate_with_def(value, reg_def)
@@ -198,7 +198,7 @@ class RDAStateInitializer:
198
198
  ml_def = Definition(ml_atom, ex_loc, tags={ParameterTag(function=func_addr)})
199
199
  state.all_definitions.add(ml_def)
200
200
  if state.analysis is not None:
201
- state.analysis.model.add_def(ml_def, ex_loc)
201
+ state.analysis.model.add_def(ml_def)
202
202
  ml = state.annotate_with_def(state.top(self.arch.bits), ml_def)
203
203
  stack_address = state.get_stack_address(state.stack_address(arg.stack_offset))
204
204
  state.stack.store(stack_address, ml, endness=self.arch.memory_endness)
@@ -328,7 +328,7 @@ class ReachingDefinitionsState:
328
328
  Overwrite existing definitions w.r.t 'atom' with a dummy definition instance. A dummy definition will not be
329
329
  removed during simplification.
330
330
  """
331
- existing_defs = set(self.live_definitions.get_definitions(atom))
331
+ existing_defs = self.live_definitions.get_definitions(atom)
332
332
 
333
333
  self.live_definitions.kill_definitions(atom)
334
334
 
@@ -347,7 +347,7 @@ class ReachingDefinitionsState:
347
347
  override_codeloc: Optional[CodeLocation] = None,
348
348
  ) -> Tuple[Optional[MultiValues], Set[Definition]]:
349
349
  codeloc = override_codeloc or self.codeloc
350
- existing_defs = set(self.live_definitions.get_definitions(atom))
350
+ existing_defs = self.live_definitions.get_definitions(atom)
351
351
  mv = self.live_definitions.kill_and_add_definition(
352
352
  atom, codeloc, data, dummy=dummy, tags=tags, endness=endness, annotated=annotated
353
353
  )
@@ -417,7 +417,7 @@ class ReachingDefinitionsState:
417
417
  for def_ in existing_defs:
418
418
  self.analysis.model.kill_def(def_)
419
419
  for def_ in defs:
420
- self.analysis.model.add_def(def_, codeloc)
420
+ self.analysis.model.add_def(def_)
421
421
 
422
422
  return mv, defs
423
423
 
@@ -450,8 +450,8 @@ class ReachingDefinitionsState:
450
450
  self.codeloc_uses.add(definition)
451
451
  self.live_definitions.add_register_use_by_def(definition, self.codeloc, expr=expr)
452
452
 
453
- def add_stack_use(self, stack_offset: int, size: int, endness, expr: Optional[Any] = None) -> None:
454
- defs = self.live_definitions.get_stack_definitions(stack_offset, size, endness)
453
+ def add_stack_use(self, stack_offset: int, size: int, expr: Optional[Any] = None) -> None:
454
+ defs = self.live_definitions.get_stack_definitions(stack_offset, size)
455
455
  self.add_stack_use_by_defs(defs, expr=expr)
456
456
 
457
457
  def add_stack_use_by_defs(self, defs: Iterable[Definition], expr: Optional[Any] = None):
@@ -459,8 +459,8 @@ class ReachingDefinitionsState:
459
459
  self.codeloc_uses.add(definition)
460
460
  self.live_definitions.add_stack_use_by_def(definition, self.codeloc, expr=expr)
461
461
 
462
- def add_heap_use(self, heap_offset: int, size: int, endness, expr: Optional[Any] = None) -> None:
463
- defs = self.live_definitions.get_heap_definitions(heap_offset, size, endness)
462
+ def add_heap_use(self, heap_offset: int, size: int, expr: Optional[Any] = None) -> None:
463
+ defs = self.live_definitions.get_heap_definitions(heap_offset, size)
464
464
  self.add_heap_use_by_defs(defs, expr=expr)
465
465
 
466
466
  def add_heap_use_by_defs(self, defs: Iterable[Definition], expr: Optional[Any] = None):
@@ -477,10 +477,8 @@ class ReachingDefinitionsState:
477
477
  self.codeloc_uses.add(definition)
478
478
  self.live_definitions.add_memory_use_by_def(definition, self.codeloc, expr=expr)
479
479
 
480
- def get_definitions(
481
- self, atom: Union[Atom, Definition, Iterable[Atom], Iterable[Definition]]
482
- ) -> Iterable[Definition]:
483
- yield from self.live_definitions.get_definitions(atom)
480
+ def get_definitions(self, atom: Union[Atom, Definition, Iterable[Atom], Iterable[Definition]]) -> Set[Definition]:
481
+ return self.live_definitions.get_definitions(atom)
484
482
 
485
483
  def get_values(self, spec: Union[Atom, Definition, Iterable[Atom]]) -> Optional[MultiValues]:
486
484
  return self.live_definitions.get_values(spec)
@@ -1,9 +1,7 @@
1
1
  # pylint:disable=missing-class-docstring
2
- from typing import Dict, Any, Optional, TYPE_CHECKING
2
+ from typing import Dict, Any, Optional, Set, TYPE_CHECKING
3
3
  from itertools import count
4
4
 
5
- from ...utils.cowdict import ChainMapCOW
6
-
7
5
  if TYPE_CHECKING:
8
6
  from angr.sim_variable import SimVariable
9
7
 
@@ -340,25 +338,20 @@ class DerivedTypeVariable(TypeVariable):
340
338
 
341
339
 
342
340
  class TypeVariables:
343
- __slots__ = ("_typevars",)
341
+ __slots__ = (
342
+ "_typevars",
343
+ "_last_typevars",
344
+ )
344
345
 
345
346
  def __init__(self):
346
- self._typevars: Dict["SimVariable", TypeVariable] = ChainMapCOW(collapse_threshold=25)
347
-
348
- def merge(self, tvs):
349
- merged = TypeVariables()
350
-
351
- # TODO: Replace this with a real lattice-based merging
352
- merged._typevars = self._typevars.copy()
353
- if tvs._typevars:
354
- merged._typevars = merged._typevars.clean()
355
- merged._typevars.update(tvs._typevars)
356
-
357
- return merged
347
+ self._typevars: Dict["SimVariable", Set[TypeVariable]] = {}
348
+ self._last_typevars: Dict[SimVariable, TypeVariable] = {}
358
349
 
359
350
  def copy(self):
360
351
  copied = TypeVariables()
361
- copied._typevars = self._typevars.copy()
352
+ for var, typevars in self._typevars.items():
353
+ copied._typevars[var] = typevars.copy()
354
+ copied._last_typevars = self._last_typevars.copy()
362
355
  return copied
363
356
 
364
357
  def __repr__(self):
@@ -369,27 +362,24 @@ class TypeVariables:
369
362
  return "{TypeVars: %d items}" % len(self._typevars)
370
363
 
371
364
  def add_type_variable(self, var: "SimVariable", codeloc, typevar: TypeVariable): # pylint:disable=unused-argument
372
- # if var not in self._typevars:
373
- # self._typevars[var] = { }
374
-
375
- # assert codeloc not in self._typevars[var]
376
- # self._typevars[var][codeloc] = typevar
377
- self._typevars = self._typevars.clean()
378
- self._typevars[var] = typevar
365
+ if var not in self._typevars:
366
+ self._typevars[var] = set()
367
+ elif typevar in self._typevars[var]:
368
+ return
369
+ self._typevars[var].add(typevar)
370
+ self._last_typevars[var] = typevar
379
371
 
380
372
  def get_type_variable(self, var, codeloc): # pylint:disable=unused-argument
381
- return self._typevars[var] # [codeloc]
373
+ return self._last_typevars[var]
382
374
 
383
375
  def has_type_variable_for(self, var: "SimVariable", codeloc): # pylint:disable=unused-argument
384
- if var not in self._typevars:
385
- return False
386
- return True
376
+ return var in self._typevars
387
377
  # if codeloc not in self._typevars[var]:
388
378
  # return False
389
379
  # return True
390
380
 
391
381
  def __getitem__(self, var):
392
- return self._typevars[var]
382
+ return self._last_typevars[var]
393
383
 
394
384
  def __contains__(self, var):
395
385
  return var in self._typevars
@@ -1,5 +1,5 @@
1
1
  # pylint:disable=wrong-import-position,wrong-import-order
2
- from typing import Optional, List, Tuple, Union
2
+ from typing import Optional, List, Tuple, Union, DefaultDict, Set
3
3
  import logging
4
4
  from collections import defaultdict
5
5
 
@@ -17,7 +17,7 @@ from ...knowledge_plugins import Function
17
17
  from ...sim_variable import SimStackVariable, SimRegisterVariable, SimVariable, SimMemoryVariable
18
18
  from ...engines.vex.claripy.irop import vexop_to_simop
19
19
  from angr.analyses import ForwardAnalysis, visitors
20
- from ..typehoon.typevars import Equivalence, TypeVariable
20
+ from ..typehoon.typevars import Equivalence, TypeVariable, TypeVariables
21
21
  from .variable_recovery_base import VariableRecoveryBase, VariableRecoveryStateBase
22
22
  from .engine_vex import SimEngineVRVEX
23
23
  from .engine_ail import SimEngineVRAIL
@@ -86,9 +86,9 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
86
86
  stack_region=self.stack_region.copy(),
87
87
  register_region=self.register_region.copy(),
88
88
  global_region=self.global_region.copy(),
89
- typevars=self.typevars.copy(),
90
- type_constraints=self.type_constraints.copy(),
91
- delayed_type_constraints=self.delayed_type_constraints.copy(),
89
+ typevars=self.typevars,
90
+ type_constraints=self.type_constraints,
91
+ delayed_type_constraints=self.delayed_type_constraints,
92
92
  stack_offset_typevars=dict(self.stack_offset_typevars),
93
93
  project=self.project,
94
94
  ret_val_size=self.ret_val_size,
@@ -125,26 +125,17 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
125
125
  merged_global_region.set_state(self)
126
126
  merge_occurred |= merged_global_region.merge([other.global_region for other in others], None)
127
127
 
128
- merged_typevars = self.typevars
129
- merged_typeconstraints = self.type_constraints.copy()
130
- delayed_typeconstraints = self.delayed_type_constraints.copy().clean()
131
- for other in others:
132
- merged_typevars = merged_typevars.merge(other.typevars)
133
- merged_typeconstraints |= other.type_constraints
134
- for v, cons in other.delayed_type_constraints.items():
135
- delayed_typeconstraints[v] |= cons
136
-
137
- merge_occurred |= self.typevars != merged_typevars
138
- merge_occurred |= self.type_constraints != merged_typeconstraints
139
- merge_occurred |= self.delayed_type_constraints != delayed_typeconstraints
128
+ typevars = self.typevars
129
+ type_constraints = self.type_constraints
130
+ delayed_typeconstraints = self.delayed_type_constraints
140
131
 
141
132
  # add subtype constraints for all replacements
142
133
  for v0, v1 in self.phi_variables.items():
143
134
  # v0 will be replaced by v1
144
- if not merged_typevars.has_type_variable_for(v1, None):
145
- merged_typevars.add_type_variable(v1, None, TypeVariable())
146
- if not merged_typevars.has_type_variable_for(v0, None):
147
- merged_typevars.add_type_variable(v0, None, TypeVariable())
135
+ if not typevars.has_type_variable_for(v1, None):
136
+ typevars.add_type_variable(v1, None, TypeVariable())
137
+ if not typevars.has_type_variable_for(v0, None):
138
+ typevars.add_type_variable(v0, None, TypeVariable())
148
139
  # Assuming v2 = phi(v0, v1), then we know that v0_typevar == v1_typevar == v2_typevar
149
140
  # However, it's possible that neither v0 nor v1 will ever be used in future blocks, which not only makes
150
141
  # this phi function useless, but also leads to the incorrect assumption that v1_typevar == v2_typevar.
@@ -152,9 +143,7 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
152
143
  # when v1 (the new variable that will end up in the state) is ever used in the future.
153
144
 
154
145
  # create an equivalence relationship
155
- equivalence = Equivalence(
156
- merged_typevars.get_type_variable(v1, None), merged_typevars.get_type_variable(v0, None)
157
- )
146
+ equivalence = Equivalence(typevars.get_type_variable(v1, None), typevars.get_type_variable(v0, None))
158
147
  delayed_typeconstraints[v1].add(equivalence)
159
148
 
160
149
  stack_offset_typevars = {}
@@ -173,7 +162,7 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
173
162
  else:
174
163
  typevar = TypeVariable()
175
164
  for orig_typevar in all_typevars:
176
- merged_typeconstraints.add(Equivalence(orig_typevar, typevar))
165
+ type_constraints.add(Equivalence(orig_typevar, typevar))
177
166
  stack_offset_typevars[offset] = typevar
178
167
 
179
168
  ret_val_size = self.ret_val_size
@@ -195,8 +184,8 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
195
184
  stack_region=merged_stack_region,
196
185
  register_region=merged_register_region,
197
186
  global_region=merged_global_region,
198
- typevars=merged_typevars,
199
- type_constraints=merged_typeconstraints,
187
+ typevars=typevars,
188
+ type_constraints=type_constraints,
200
189
  delayed_type_constraints=delayed_typeconstraints,
201
190
  stack_offset_typevars=stack_offset_typevars,
202
191
  project=self.project,
@@ -205,6 +194,9 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
205
194
 
206
195
  return state, merge_occurred
207
196
 
197
+ def downsize(self) -> None:
198
+ pass
199
+
208
200
  #
209
201
  # Util methods
210
202
  #
@@ -277,8 +269,10 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
277
269
  self._node_iterations = defaultdict(int)
278
270
 
279
271
  self._node_to_cc = {}
280
- self.var_to_typevars = defaultdict(set)
272
+ self.var_to_typevars: DefaultDict[SimVariable, Set[TypeVariable]] = defaultdict(set)
273
+ self.typevars = None
281
274
  self.type_constraints = None
275
+ self.delayed_type_constraints = None
282
276
  self.ret_val_size = None
283
277
 
284
278
  self._analyze()
@@ -293,7 +287,9 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
293
287
  #
294
288
 
295
289
  def _pre_analysis(self):
290
+ self.typevars = TypeVariables()
296
291
  self.type_constraints = set()
292
+ self.delayed_type_constraints = defaultdict(set)
297
293
 
298
294
  self.initialize_dominance_frontiers()
299
295
 
@@ -321,6 +317,9 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
321
317
  self.project.arch,
322
318
  self.function,
323
319
  project=self.project,
320
+ typevars=self.typevars,
321
+ type_constraints=self.type_constraints,
322
+ delayed_type_constraints=self.delayed_type_constraints,
324
323
  )
325
324
  initial_sp = state.stack_address(self.project.arch.bytes if self.project.arch.call_pushes_ret else 0)
326
325
  if self.project.arch.sp_offset is not None:
@@ -434,9 +433,6 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
434
433
  self._process_block(state, block)
435
434
 
436
435
  self._node_iterations[block_key] += 1
437
- self.type_constraints |= state.type_constraints
438
- for var, typevar in state.typevars._typevars.items():
439
- self.var_to_typevars[var].add(typevar)
440
436
 
441
437
  if state.ret_val_size is not None:
442
438
  if self.ret_val_size is None or self.ret_val_size < state.ret_val_size:
@@ -467,6 +463,10 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
467
463
  if self._unify_variables:
468
464
  self.variable_manager[self.function.addr].unify_variables()
469
465
 
466
+ # fill in var_to_typevars
467
+ for var, typevar_set in self.typevars._typevars.items():
468
+ self.var_to_typevars[var] = typevar_set
469
+
470
470
  # unify type variables for global variables
471
471
  for var, typevars in self.var_to_typevars.items():
472
472
  if len(typevars) > 1 and isinstance(var, SimMemoryVariable) and not isinstance(var, SimStackVariable):
@@ -476,6 +476,8 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
476
476
 
477
477
  self.variable_manager[self.function.addr].ret_val_size = self.ret_val_size
478
478
 
479
+ self.delayed_type_constraints = None
480
+
479
481
  #
480
482
  # Private methods
481
483
  #
@@ -547,7 +547,7 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
547
547
  to_size = expr_1.size()
548
548
  if signed:
549
549
  quotient = expr_0.SDiv(claripy.SignExt(from_size - to_size, expr_1))
550
- remainder = expr_1.SMod(claripy.SignExt(from_size - to_size, expr_1))
550
+ remainder = expr_0.SMod(claripy.SignExt(from_size - to_size, expr_1))
551
551
  quotient_size = to_size
552
552
  remainder_size = to_size
553
553
  return claripy.Concat(
angr/keyed_region.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  import weakref
3
- from typing import Union, TYPE_CHECKING
3
+ from typing import Union, Optional, Tuple, TYPE_CHECKING
4
4
 
5
5
  from sortedcontainers import SortedDict
6
6
 
@@ -133,7 +133,7 @@ class KeyedRegion:
133
133
  self._storage, om, self._phi_node_contains = s
134
134
  self._object_mapping = weakref.WeakValueDictionary(om)
135
135
 
136
- def _get_container(self, offset):
136
+ def _get_container(self, offset) -> Tuple[int, Optional[RegionObject]]:
137
137
  try:
138
138
  base_offset = next(self._storage.irange(maximum=offset, reverse=True))
139
139
  except StopIteration:
@@ -419,7 +419,23 @@ class KeyedRegion:
419
419
 
420
420
  # is there a region item that begins before the start and overlaps with this variable?
421
421
  floor_key, floor_item = self._get_container(start)
422
- if floor_item is not None and floor_key not in overlapping_items:
422
+ if floor_item is None:
423
+ # fast path: just insert it
424
+ self._storage[start] = RegionObject(start, object_size, {stored_object})
425
+ return
426
+
427
+ # fast path: if there is a perfect overlap, just update the item
428
+ if len(overlapping_items) == 1 and floor_item.start == start and floor_item.end == end:
429
+ if overwrite:
430
+ floor_item.set_object(stored_object)
431
+ elif merge_to_top is False and top is None:
432
+ floor_item.add_object(stored_object)
433
+ else:
434
+ self._add_object_with_check(floor_item, stored_object, merge_to_top=merge_to_top, top=top)
435
+ return
436
+
437
+ # slower path: there are multiple overlapping items
438
+ if floor_key not in overlapping_items:
423
439
  # insert it into the beginning
424
440
  overlapping_items.insert(0, floor_key)
425
441
 
@@ -648,6 +648,14 @@ class Function(Serializable):
648
648
  """
649
649
  return self.binary.loader.find_symbol(self.addr)
650
650
 
651
+ @property
652
+ def pseudocode(self) -> str:
653
+ """
654
+ :return: the function's pseudocode
655
+ """
656
+ dec = self.project.analyses.Decompiler(self, cfg=self._function_manager._kb.cfgs.get_most_accurate())
657
+ return dec.codegen.text
658
+
651
659
  def add_jumpout_site(self, node):
652
660
  """
653
661
  Add a custom jumpout site.