angr 9.2.135__py3-none-macosx_10_9_x86_64.whl → 9.2.137__py3-none-macosx_10_9_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of angr might be problematic. Click here for more details.

Files changed (199) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/__init__.py +3 -7
  3. angr/analyses/analysis.py +4 -0
  4. angr/analyses/backward_slice.py +1 -2
  5. angr/analyses/binary_optimizer.py +3 -4
  6. angr/analyses/bindiff.py +4 -6
  7. angr/analyses/boyscout.py +1 -3
  8. angr/analyses/callee_cleanup_finder.py +4 -4
  9. angr/analyses/calling_convention/calling_convention.py +6 -4
  10. angr/analyses/calling_convention/fact_collector.py +10 -3
  11. angr/analyses/cdg.py +1 -2
  12. angr/analyses/cfg/cfb.py +1 -3
  13. angr/analyses/cfg/cfg.py +2 -2
  14. angr/analyses/cfg/cfg_base.py +40 -68
  15. angr/analyses/cfg/cfg_emulated.py +1 -104
  16. angr/analyses/cfg/cfg_fast.py +90 -27
  17. angr/analyses/cfg/cfg_fast_soot.py +1 -1
  18. angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
  19. angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +46 -10
  20. angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +5 -1
  21. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +65 -14
  22. angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
  23. angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +24 -5
  24. angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +2 -5
  25. angr/analyses/class_identifier.py +1 -2
  26. angr/analyses/complete_calling_conventions.py +3 -0
  27. angr/analyses/congruency_check.py +2 -3
  28. angr/analyses/data_dep/data_dependency_analysis.py +2 -2
  29. angr/analyses/ddg.py +1 -4
  30. angr/analyses/decompiler/ail_simplifier.py +15 -5
  31. angr/analyses/decompiler/block_simplifier.py +2 -2
  32. angr/analyses/decompiler/ccall_rewriters/__init__.py +2 -0
  33. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
  34. angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +69 -0
  35. angr/analyses/decompiler/clinic.py +119 -72
  36. angr/analyses/decompiler/condition_processor.py +2 -0
  37. angr/analyses/decompiler/decompiler.py +1 -0
  38. angr/analyses/decompiler/dephication/dephication_base.py +2 -0
  39. angr/analyses/decompiler/dephication/rewriting_engine.py +8 -6
  40. angr/analyses/decompiler/dephication/seqnode_dephication.py +10 -1
  41. angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
  42. angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +2 -2
  43. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +1 -1
  44. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
  45. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +1 -2
  46. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +1 -1
  47. angr/analyses/decompiler/sequence_walker.py +6 -2
  48. angr/analyses/decompiler/ssailification/rewriting.py +11 -1
  49. angr/analyses/decompiler/ssailification/rewriting_engine.py +56 -19
  50. angr/analyses/decompiler/ssailification/ssailification.py +13 -3
  51. angr/analyses/decompiler/ssailification/traversal.py +28 -2
  52. angr/analyses/decompiler/ssailification/traversal_state.py +6 -1
  53. angr/analyses/decompiler/structured_codegen/c.py +44 -21
  54. angr/analyses/decompiler/structuring/phoenix.py +118 -15
  55. angr/analyses/decompiler/utils.py +113 -8
  56. angr/analyses/disassembly.py +5 -5
  57. angr/analyses/fcp/__init__.py +4 -0
  58. angr/analyses/fcp/fcp.py +429 -0
  59. angr/analyses/identifier/identify.py +1 -3
  60. angr/analyses/loopfinder.py +4 -3
  61. angr/analyses/patchfinder.py +1 -1
  62. angr/analyses/propagator/engine_base.py +4 -3
  63. angr/analyses/propagator/propagator.py +14 -53
  64. angr/analyses/reaching_definitions/function_handler.py +1 -1
  65. angr/analyses/reassembler.py +1 -2
  66. angr/analyses/s_liveness.py +5 -1
  67. angr/analyses/s_propagator.py +26 -7
  68. angr/analyses/s_reaching_definitions/s_rda_model.py +2 -1
  69. angr/analyses/s_reaching_definitions/s_rda_view.py +20 -1
  70. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +11 -1
  71. angr/analyses/soot_class_hierarchy.py +1 -2
  72. angr/analyses/stack_pointer_tracker.py +29 -3
  73. angr/analyses/static_hooker.py +1 -2
  74. angr/analyses/typehoon/simple_solver.py +2 -2
  75. angr/analyses/variable_recovery/engine_ail.py +19 -7
  76. angr/analyses/variable_recovery/engine_base.py +16 -14
  77. angr/analyses/variable_recovery/engine_vex.py +2 -2
  78. angr/analyses/variable_recovery/variable_recovery_fast.py +23 -3
  79. angr/analyses/veritesting.py +4 -7
  80. angr/analyses/vfg.py +1 -1
  81. angr/analyses/vsa_ddg.py +1 -2
  82. angr/block.py +62 -22
  83. angr/callable.py +1 -3
  84. angr/calling_conventions.py +3 -3
  85. angr/codenode.py +5 -1
  86. angr/concretization_strategies/__init__.py +1 -83
  87. angr/concretization_strategies/any.py +2 -1
  88. angr/concretization_strategies/any_named.py +1 -1
  89. angr/concretization_strategies/base.py +81 -0
  90. angr/concretization_strategies/controlled_data.py +2 -1
  91. angr/concretization_strategies/eval.py +2 -1
  92. angr/concretization_strategies/logging.py +3 -1
  93. angr/concretization_strategies/max.py +2 -1
  94. angr/concretization_strategies/nonzero.py +2 -1
  95. angr/concretization_strategies/nonzero_range.py +2 -1
  96. angr/concretization_strategies/norepeats.py +2 -1
  97. angr/concretization_strategies/norepeats_range.py +2 -1
  98. angr/concretization_strategies/range.py +2 -1
  99. angr/concretization_strategies/signed_add.py +2 -1
  100. angr/concretization_strategies/single.py +2 -1
  101. angr/concretization_strategies/solutions.py +2 -1
  102. angr/concretization_strategies/unlimited_range.py +2 -1
  103. angr/engines/__init__.py +8 -5
  104. angr/engines/engine.py +3 -5
  105. angr/engines/failure.py +4 -5
  106. angr/engines/pcode/emulate.py +1 -1
  107. angr/engines/pcode/lifter.py +31 -18
  108. angr/engines/procedure.py +5 -7
  109. angr/engines/soot/expressions/__init__.py +20 -23
  110. angr/engines/soot/expressions/base.py +4 -4
  111. angr/engines/soot/expressions/invoke.py +1 -2
  112. angr/engines/soot/statements/__init__.py +10 -12
  113. angr/engines/soot/values/__init__.py +10 -12
  114. angr/engines/soot/values/arrayref.py +3 -3
  115. angr/engines/soot/values/instancefieldref.py +3 -2
  116. angr/engines/successors.py +18 -12
  117. angr/engines/syscall.py +4 -6
  118. angr/engines/unicorn.py +3 -2
  119. angr/engines/vex/claripy/ccall.py +8 -10
  120. angr/engines/vex/claripy/datalayer.py +4 -5
  121. angr/engines/vex/lifter.py +9 -6
  122. angr/exploration_techniques/__init__.py +0 -2
  123. angr/exploration_techniques/spiller.py +1 -3
  124. angr/exploration_techniques/stochastic.py +2 -3
  125. angr/factory.py +3 -9
  126. angr/flirt/build_sig.py +8 -15
  127. angr/knowledge_plugins/cfg/cfg_model.py +20 -17
  128. angr/knowledge_plugins/functions/function.py +70 -79
  129. angr/knowledge_plugins/functions/function_manager.py +8 -7
  130. angr/knowledge_plugins/functions/function_parser.py +1 -1
  131. angr/knowledge_plugins/functions/soot_function.py +21 -24
  132. angr/knowledge_plugins/propagations/propagation_model.py +4 -5
  133. angr/knowledge_plugins/propagations/states.py +0 -511
  134. angr/knowledge_plugins/variables/variable_manager.py +16 -10
  135. angr/lib/angr_native.dylib +0 -0
  136. angr/procedures/libc/memcpy.py +4 -4
  137. angr/procedures/procedure_dict.py +3 -2
  138. angr/protos/__init__.py +2 -5
  139. angr/protos/cfg_pb2.py +21 -18
  140. angr/protos/function_pb2.py +17 -14
  141. angr/protos/primitives_pb2.py +44 -39
  142. angr/protos/variables_pb2.py +36 -31
  143. angr/protos/xrefs_pb2.py +15 -12
  144. angr/sim_procedure.py +15 -16
  145. angr/sim_variable.py +13 -1
  146. angr/simos/__init__.py +2 -0
  147. angr/simos/javavm.py +4 -6
  148. angr/simos/xbox.py +32 -0
  149. angr/state_plugins/__init__.py +0 -2
  150. angr/state_plugins/callstack.py +4 -4
  151. angr/state_plugins/cgc.py +3 -2
  152. angr/state_plugins/gdb.py +6 -5
  153. angr/state_plugins/globals.py +1 -2
  154. angr/state_plugins/heap/heap_brk.py +1 -2
  155. angr/state_plugins/history.py +10 -12
  156. angr/state_plugins/inspect.py +3 -5
  157. angr/state_plugins/libc.py +2 -2
  158. angr/state_plugins/log.py +8 -10
  159. angr/state_plugins/loop_data.py +1 -2
  160. angr/state_plugins/posix.py +7 -7
  161. angr/state_plugins/preconstrainer.py +2 -3
  162. angr/state_plugins/scratch.py +5 -8
  163. angr/state_plugins/sim_action.py +3 -3
  164. angr/state_plugins/solver.py +8 -3
  165. angr/state_plugins/symbolizer.py +5 -4
  166. angr/state_plugins/uc_manager.py +3 -3
  167. angr/state_plugins/unicorn_engine.py +5 -1
  168. angr/state_plugins/view.py +3 -5
  169. angr/storage/file.py +3 -5
  170. angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
  171. angr/storage/memory_mixins/bvv_conversion_mixin.py +3 -3
  172. angr/storage/memory_mixins/clouseau_mixin.py +1 -3
  173. angr/storage/memory_mixins/name_resolution_mixin.py +1 -3
  174. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +13 -15
  175. angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -22
  176. angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
  177. angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
  178. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
  179. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
  180. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +3 -4
  181. angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
  182. angr/storage/memory_mixins/smart_find_mixin.py +1 -1
  183. angr/storage/memory_mixins/underconstrained_mixin.py +1 -1
  184. angr/storage/memory_mixins/unwrapper_mixin.py +1 -3
  185. angr/utils/enums_conv.py +28 -12
  186. angr/utils/segment_list.py +25 -22
  187. angr/utils/timing.py +18 -1
  188. angr/vaults.py +5 -6
  189. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/METADATA +7 -7
  190. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/RECORD +194 -192
  191. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/WHEEL +1 -1
  192. angr/analyses/propagator/outdated_definition_walker.py +0 -159
  193. angr/analyses/propagator/tmpvar_finder.py +0 -18
  194. angr/engines/concrete.py +0 -180
  195. angr/exploration_techniques/symbion.py +0 -80
  196. angr/state_plugins/concrete.py +0 -295
  197. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/LICENSE +0 -0
  198. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/entry_points.txt +0 -0
  199. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/top_level.txt +0 -0
angr/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
  # pylint: disable=wrong-import-position
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "9.2.135"
5
+ __version__ = "9.2.137"
6
6
 
7
7
  if bytes is str:
8
8
  raise Exception(
angr/analyses/__init__.py CHANGED
@@ -1,13 +1,7 @@
1
1
  # " pylint:disable=wrong-import-position
2
2
  from __future__ import annotations
3
3
 
4
- from .analysis import Analysis, AnalysesHub
5
-
6
-
7
- def register_analysis(cls, name):
8
- AnalysesHub.register_default(name, cls)
9
-
10
-
4
+ from .analysis import Analysis, AnalysesHub, register_analysis
11
5
  from .forward_analysis import ForwardAnalysis, visitors
12
6
  from .propagator import PropagatorAnalysis
13
7
  from .cfg import CFGFast, CFGEmulated, CFG, CFGArchOptions, CFGFastSoot
@@ -54,6 +48,7 @@ from .patchfinder import PatchFinderAnalysis
54
48
  from .pathfinder import Pathfinder
55
49
  from .smc import SelfModifyingCodeAnalysis
56
50
  from .unpacker import PackingDetector
51
+ from .fcp import FastConstantPropagation
57
52
  from . import deobfuscator
58
53
 
59
54
 
@@ -85,6 +80,7 @@ __all__ = (
85
80
  "Disassembly",
86
81
  "DominanceFrontier",
87
82
  "FactCollector",
83
+ "FastConstantPropagation",
88
84
  "FlirtAnalysis",
89
85
  "ForwardAnalysis",
90
86
  "Identifier",
angr/analyses/analysis.py CHANGED
@@ -409,3 +409,7 @@ class Analysis:
409
409
 
410
410
  default_analyses = VendorPreset()
411
411
  AnalysesHub.register_preset("default", default_analyses)
412
+
413
+
414
+ def register_analysis(cls, name):
415
+ AnalysesHub.register_default(name, cls)
@@ -6,6 +6,7 @@ import networkx
6
6
  import pyvex
7
7
  from . import Analysis
8
8
 
9
+ from angr.analyses import AnalysesHub
9
10
  from angr.code_location import CodeLocation
10
11
  from angr.annocfg import AnnotatedCFG
11
12
  from angr.errors import AngrBackwardSlicingError
@@ -682,6 +683,4 @@ class BackwardSlice(Analysis):
682
683
  return cmp_stmt_id, cmp_tmp_id
683
684
 
684
685
 
685
- from angr.analyses import AnalysesHub
686
-
687
686
  AnalysesHub.register_default("BackwardSlice", BackwardSlice)
@@ -4,6 +4,7 @@ import re
4
4
  from typing import TYPE_CHECKING
5
5
  from collections import defaultdict
6
6
 
7
+ from angr.analyses import AnalysesHub
7
8
  from angr.knowledge_base import KnowledgeBase
8
9
  from angr.codenode import HookNode
9
10
  from angr.sim_variable import SimConstantVariable, SimRegisterVariable, SimMemoryVariable, SimStackVariable
@@ -430,7 +431,7 @@ class BinaryOptimizer(Analysis):
430
431
 
431
432
  # find out all call instructions
432
433
  call_insns = set()
433
- for src, dst, data in function.transition_graph.edges(data=True):
434
+ for src, _dst, data in function.transition_graph.edges(data=True):
434
435
  if "type" in data and data["type"] == "call":
435
436
  src_block = function._get_block(src.addr)
436
437
  call_insns.add(src_block.instruction_addrs[-1])
@@ -460,7 +461,7 @@ class BinaryOptimizer(Analysis):
460
461
  # make sure we never gets the address of those stack variables into any register
461
462
  # say, lea edx, [ebp-0x4] is forbidden
462
463
  # check all edges in data graph
463
- for src, dst, data in data_graph.edges(data=True):
464
+ for src, dst in data_graph.edges():
464
465
  if (
465
466
  isinstance(dst.variable, SimRegisterVariable)
466
467
  and dst.variable.reg != ebp_offset
@@ -666,6 +667,4 @@ class BinaryOptimizer(Analysis):
666
667
  self.dead_assignments.append(da)
667
668
 
668
669
 
669
- from angr.analyses import AnalysesHub
670
-
671
670
  AnalysesHub.register_default("BinaryOptimizer", BinaryOptimizer)
angr/analyses/bindiff.py CHANGED
@@ -3,17 +3,17 @@ import logging
3
3
  import math
4
4
  import types
5
5
  from collections import deque, defaultdict
6
+ from typing import TYPE_CHECKING
6
7
 
7
8
  import networkx
8
9
 
9
- from typing import TYPE_CHECKING
10
+ from angr.analyses import AnalysesHub, Analysis, CFGEmulated
11
+ from angr.errors import SimEngineError, SimMemoryError
12
+
10
13
 
11
14
  if TYPE_CHECKING:
12
15
  from angr.knowledge_plugins import Function
13
16
 
14
- from . import Analysis, CFGEmulated
15
-
16
- from angr.errors import SimEngineError, SimMemoryError
17
17
 
18
18
  # todo include an explanation of the algorithm
19
19
  # todo include a method that detects any change other than constants
@@ -1234,6 +1234,4 @@ class BinDiff(Analysis):
1234
1234
  return matches
1235
1235
 
1236
1236
 
1237
- from angr.analyses import AnalysesHub
1238
-
1239
1237
  AnalysesHub.register_default("BinDiff", BinDiff)
angr/analyses/boyscout.py CHANGED
@@ -6,7 +6,7 @@ from collections import defaultdict
6
6
  from archinfo import all_arches
7
7
  from archinfo.arch_arm import is_arm_arch
8
8
 
9
- from . import Analysis
9
+ from angr.analyses import AnalysesHub, Analysis
10
10
 
11
11
 
12
12
  l = logging.getLogger(name=__name__)
@@ -73,6 +73,4 @@ class BoyScout(Analysis):
73
73
  l.debug("The architecture should be %s with %s", self.arch, self.endianness)
74
74
 
75
75
 
76
- from angr.analyses import AnalysesHub
77
-
78
76
  AnalysesHub.register_default("BoyScout", BoyScout)
@@ -1,9 +1,11 @@
1
1
  from __future__ import annotations
2
- from . import Analysis
3
- from angr import SIM_PROCEDURES
4
2
 
5
3
  import logging
6
4
 
5
+ from angr import SIM_PROCEDURES
6
+ from angr.analyses import AnalysesHub, Analysis
7
+
8
+
7
9
  l = logging.getLogger(name=__name__)
8
10
 
9
11
 
@@ -69,6 +71,4 @@ class CalleeCleanupFinder(Analysis):
69
71
  return None
70
72
 
71
73
 
72
- from angr.analyses import AnalysesHub
73
-
74
74
  AnalysesHub.register_default("CalleeCleanupFinder", CalleeCleanupFinder)
@@ -436,7 +436,8 @@ class CallingConventionAnalysis(Analysis):
436
436
  if caller.is_simprocedure or caller.is_alignment:
437
437
  # do not analyze SimProcedures or alignment stubs
438
438
  continue
439
- call_sites_by_function[caller].append((src.addr, src.instruction_addrs[-1]))
439
+ if src.instruction_addrs:
440
+ call_sites_by_function[caller].append((src.addr, src.instruction_addrs[-1]))
440
441
 
441
442
  call_sites_by_function_list = sorted(call_sites_by_function.items(), key=lambda x: x[0].addr)[
442
443
  :max_analyzing_callsites
@@ -923,9 +924,10 @@ class CallingConventionAnalysis(Analysis):
923
924
  if not set(spilled_regs).issubset(set(allowed_spilled_regs)):
924
925
  return False, None
925
926
 
926
- for i, reg in enumerate(allowed_spilled_regs):
927
- if reg in spilled_regs:
928
- break
927
+ i = next(
928
+ (i for i, reg in enumerate(allowed_spilled_regs) if reg in spilled_regs),
929
+ len(allowed_spilled_regs),
930
+ )
929
931
 
930
932
  return True, i
931
933
 
@@ -276,13 +276,21 @@ class FactCollector(Analysis):
276
276
  call_succ, ret_succ = None, None
277
277
  for _, succ, data in func_graph.out_edges(node, data=True):
278
278
  edge_type = data.get("type")
279
+ outside = data.get("outside", False)
279
280
  if succ not in traversed and depth + 1 <= self._max_depth:
280
281
  if edge_type == "fake_return":
281
282
  ret_succ = succ
282
- elif edge_type == "transition":
283
+ elif edge_type == "transition" and not outside:
283
284
  successor_added = True
284
285
  queue.append((depth + 1, state.copy(), succ, None))
285
- elif edge_type == "call":
286
+ elif edge_type == "call" or (edge_type == "transition" and outside):
287
+ # a call or a tail-call
288
+ if not isinstance(succ, Function):
289
+ if self.kb.functions.contains_addr(succ.addr):
290
+ succ = self.kb.functions.get_by_addr(succ.addr)
291
+ else:
292
+ # not sure who we are calling
293
+ continue
286
294
  call_succ = succ
287
295
  if call_succ is not None:
288
296
  successor_added = True
@@ -297,7 +305,6 @@ class FactCollector(Analysis):
297
305
  try:
298
306
  arg_locs = func.calling_convention.arg_locs(func.prototype)
299
307
  except (TypeError, ValueError):
300
- func.prototype = None
301
308
  return
302
309
 
303
310
  if None in arg_locs:
angr/analyses/cdg.py CHANGED
@@ -3,6 +3,7 @@ import logging
3
3
 
4
4
  import networkx
5
5
 
6
+ from angr.analyses import AnalysesHub
6
7
  from angr.utils.graph import compute_dominance_frontier, PostDominators, TemporaryNode
7
8
  from . import Analysis
8
9
 
@@ -185,6 +186,4 @@ class CDG(Analysis):
185
186
  _l.debug("%s is not in post dominator dict.", b2)
186
187
 
187
188
 
188
- from angr.analyses import AnalysesHub
189
-
190
189
  AnalysesHub.register_default("CDG", CDG)
angr/analyses/cfg/cfb.py CHANGED
@@ -6,9 +6,9 @@ from collections.abc import Callable
6
6
  import cle
7
7
  from cle.backends.externs import KernelObject, ExternObject
8
8
  from cle.backends.tls.elf_tls import ELFTLSObject
9
-
10
9
  from sortedcontainers import SortedDict
11
10
 
11
+ from angr.analyses import AnalysesHub
12
12
  from angr.knowledge_plugins.cfg.memory_data import MemoryDataSort, MemoryData
13
13
  from angr.analyses.analysis import Analysis
14
14
 
@@ -424,7 +424,5 @@ class CFBlanket(Analysis):
424
424
  addr = max_addr
425
425
 
426
426
 
427
- from angr.analyses import AnalysesHub
428
-
429
427
  AnalysesHub.register_default("CFB", CFBlanket)
430
428
  AnalysesHub.register_default("CFBlanket", CFBlanket)
angr/analyses/cfg/cfg.py CHANGED
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
+
2
3
  import sys
3
4
 
5
+ from angr.analyses import AnalysesHub
4
6
  from .cfg_fast import CFGFast
5
7
 
6
8
 
@@ -69,6 +71,4 @@ class CFG(CFGFast): # pylint: disable=abstract-method
69
71
  CFGFast.__init__(self, **kwargs)
70
72
 
71
73
 
72
- from angr.analyses import AnalysesHub
73
-
74
74
  AnalysesHub.register_default("CFG", CFG)
@@ -1570,13 +1570,13 @@ class CFGBase(Analysis):
1570
1570
  # TODO: Is it required that PLT stubs are always aligned by 16? If so, on what architectures and platforms is it
1571
1571
  # TODO: enforced?
1572
1572
 
1573
- tmp_functions = self.kb.functions.copy()
1573
+ tmp_functions = self.kb.functions
1574
1574
 
1575
1575
  for function in tmp_functions.values():
1576
1576
  function.mark_nonreturning_calls_endpoints()
1577
1577
  if function.returning is False:
1578
1578
  # remove all FakeRet edges that are related to this function
1579
- func_node = self.model.get_any_node(function.addr)
1579
+ func_node = self.model.get_any_node(function.addr, force_fastpath=True)
1580
1580
  if func_node is not None:
1581
1581
  callsite_nodes = [
1582
1582
  src
@@ -1588,8 +1588,8 @@ class CFGBase(Analysis):
1588
1588
  if data.get("jumpkind", None) == "Ijk_FakeRet":
1589
1589
  self.graph.remove_edge(callsite_node, dst)
1590
1590
 
1591
- # Clear old functions dict
1592
- self.kb.functions.clear()
1591
+ # Clear old functions dict by creating a new function manager
1592
+ self.kb.functions = FunctionManager(self.kb)
1593
1593
 
1594
1594
  blockaddr_to_function = {}
1595
1595
  traversed_cfg_nodes = set()
@@ -1602,7 +1602,7 @@ class CFGBase(Analysis):
1602
1602
  if jumpkind == "Ijk_Call" or jumpkind.startswith("Ijk_Sys"):
1603
1603
  function_nodes.add(dst)
1604
1604
 
1605
- entry_node = self.model.get_any_node(self._binary.entry)
1605
+ entry_node = self.model.get_any_node(self._binary.entry, force_fastpath=True)
1606
1606
  if entry_node is not None:
1607
1607
  function_nodes.add(entry_node)
1608
1608
 
@@ -1663,7 +1663,7 @@ class CFGBase(Analysis):
1663
1663
  secondary_function_nodes = set()
1664
1664
  # add all function chunks ("functions" that are not called from anywhere)
1665
1665
  for func_addr in tmp_functions:
1666
- node = self.model.get_any_node(func_addr)
1666
+ node = self.model.get_any_node(func_addr, force_fastpath=True)
1667
1667
  if node is None:
1668
1668
  continue
1669
1669
  if node.addr not in blockaddr_to_function:
@@ -1992,8 +1992,8 @@ class CFGBase(Analysis):
1992
1992
  if not transition_found:
1993
1993
  continue
1994
1994
 
1995
- cfgnode_0 = self.model.get_any_node(block_node.addr)
1996
- cfgnode_1 = self.model.get_any_node(addr_1)
1995
+ cfgnode_0 = self.model.get_any_node(block_node.addr, force_fastpath=True)
1996
+ cfgnode_1 = self.model.get_any_node(addr_1, force_fastpath=True)
1997
1997
 
1998
1998
  if cfgnode_0 is None or cfgnode_1 is None:
1999
1999
  continue
@@ -2089,7 +2089,7 @@ class CFGBase(Analysis):
2089
2089
  continue
2090
2090
  if func_addr in jumptable_entries:
2091
2091
  # is there any call edge pointing to it?
2092
- func_node = self.get_any_node(func_addr)
2092
+ func_node = self.get_any_node(func_addr, force_fastpath=True)
2093
2093
  if func_node is not None:
2094
2094
  in_edges = self.graph.in_edges(func_node, data=True)
2095
2095
  has_transition_pred = None
@@ -2128,7 +2128,7 @@ class CFGBase(Analysis):
2128
2128
  else:
2129
2129
  is_syscall = self.project.simos.is_syscall_addr(addr)
2130
2130
 
2131
- n = self.model.get_any_node(addr, is_syscall=is_syscall)
2131
+ n = self.model.get_any_node(addr, is_syscall=is_syscall, force_fastpath=True)
2132
2132
  node = addr if n is None else self._to_snippet(n)
2133
2133
 
2134
2134
  if isinstance(addr, SootAddressDescriptor):
@@ -2304,7 +2304,7 @@ class CFGBase(Analysis):
2304
2304
  src_function = self._addr_to_function(src_addr, blockaddr_to_function, known_functions)
2305
2305
 
2306
2306
  if src_addr not in src_function.block_addrs_set:
2307
- n = self.model.get_any_node(src_addr)
2307
+ n = self.model.get_any_node(src_addr, force_fastpath=True)
2308
2308
  node = src_addr if n is None else self._to_snippet(n)
2309
2309
  self.kb.functions._add_node(src_function.addr, node)
2310
2310
 
@@ -2315,7 +2315,7 @@ class CFGBase(Analysis):
2315
2315
  jumpkind = data["jumpkind"]
2316
2316
 
2317
2317
  if jumpkind == "Ijk_Ret":
2318
- n = self.model.get_any_node(src_addr)
2318
+ n = self.model.get_any_node(src_addr, force_fastpath=True)
2319
2319
  from_node = src_addr if n is None else self._to_snippet(n)
2320
2320
  self.kb.functions._add_return_from(src_function.addr, from_node, None)
2321
2321
 
@@ -2334,7 +2334,7 @@ class CFGBase(Analysis):
2334
2334
  # It must be calling a function
2335
2335
  dst_function = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
2336
2336
 
2337
- n = self.model.get_any_node(src_addr)
2337
+ n = self.model.get_any_node(src_addr, force_fastpath=True)
2338
2338
  if n is None:
2339
2339
  src_snippet = self._to_snippet(addr=src_addr, base_state=self._base_state)
2340
2340
  else:
@@ -2349,21 +2349,12 @@ class CFGBase(Analysis):
2349
2349
  else:
2350
2350
  fakeret_node = self._one_fakeret_node(all_edges)
2351
2351
 
2352
- fakeret_snippet = None if fakeret_node is None else self._to_snippet(cfg_node=fakeret_node)
2353
-
2354
2352
  if isinstance(dst_addr, SootAddressDescriptor):
2355
2353
  dst_addr = dst_addr.method
2356
2354
 
2357
- self.kb.functions._add_call_to(
2358
- src_function.addr,
2359
- src_snippet,
2360
- dst_addr,
2361
- fakeret_snippet,
2362
- syscall=is_syscall,
2363
- ins_addr=ins_addr,
2364
- stmt_idx=stmt_idx,
2365
- )
2366
-
2355
+ # determining the returning target
2356
+ return_to_outside = False
2357
+ returning_snippet = None
2367
2358
  if dst_function.returning and fakeret_node is not None:
2368
2359
  returning_target = src.addr + src.size
2369
2360
  if returning_target not in blockaddr_to_function:
@@ -2372,9 +2363,9 @@ class CFGBase(Analysis):
2372
2363
  else:
2373
2364
  self._addr_to_function(returning_target, blockaddr_to_function, known_functions)
2374
2365
 
2375
- to_outside = blockaddr_to_function[returning_target] is not src_function
2366
+ return_to_outside = blockaddr_to_function[returning_target] is not src_function
2376
2367
 
2377
- n = self.model.get_any_node(returning_target)
2368
+ n = self.model.get_any_node(returning_target, force_fastpath=True)
2378
2369
  if n is None:
2379
2370
  try:
2380
2371
  returning_snippet = self._to_snippet(addr=returning_target, base_state=self._base_state)
@@ -2384,17 +2375,28 @@ class CFGBase(Analysis):
2384
2375
  else:
2385
2376
  returning_snippet = self._to_snippet(cfg_node=n)
2386
2377
 
2387
- if returning_snippet is not None:
2388
- self.kb.functions._add_fakeret_to(
2389
- src_function.addr, src_snippet, returning_snippet, confirmed=True, to_outside=to_outside
2390
- )
2378
+ self.kb.functions._add_call_to(
2379
+ src_function.addr,
2380
+ src_snippet,
2381
+ dst_addr,
2382
+ retn_node=returning_snippet,
2383
+ syscall=is_syscall,
2384
+ ins_addr=ins_addr,
2385
+ stmt_idx=stmt_idx,
2386
+ return_to_outside=return_to_outside,
2387
+ )
2388
+
2389
+ if returning_snippet is not None:
2390
+ self.kb.functions._add_fakeret_to(
2391
+ src_function.addr, src_snippet, returning_snippet, confirmed=True, to_outside=return_to_outside
2392
+ )
2391
2393
 
2392
2394
  elif jumpkind in ("Ijk_Boring", "Ijk_InvalICache", "Ijk_Exception"):
2393
2395
  # convert src_addr and dst_addr to CodeNodes
2394
- n = self.model.get_any_node(src_addr)
2396
+ n = self.model.get_any_node(src_addr, force_fastpath=True)
2395
2397
  src_node = src_addr if n is None else self._to_snippet(cfg_node=n)
2396
2398
 
2397
- n = self.model.get_any_node(dst_addr)
2399
+ n = self.model.get_any_node(dst_addr, force_fastpath=True)
2398
2400
  dst_node = dst_addr if n is None else self._to_snippet(cfg_node=n)
2399
2401
 
2400
2402
  if self._skip_unmapped_addrs:
@@ -2460,10 +2462,10 @@ class CFGBase(Analysis):
2460
2462
 
2461
2463
  elif jumpkind == "Ijk_FakeRet":
2462
2464
  # convert src_addr and dst_addr to CodeNodes
2463
- n = self.model.get_any_node(src_addr)
2465
+ n = self.model.get_any_node(src_addr, force_fastpath=True)
2464
2466
  src_node = src_addr if n is None else self._to_snippet(n)
2465
2467
 
2466
- n = self.model.get_any_node(dst_addr)
2468
+ n = self.model.get_any_node(dst_addr, force_fastpath=True)
2467
2469
  dst_node = dst_addr if n is None else self._to_snippet(n)
2468
2470
 
2469
2471
  if dst_addr not in blockaddr_to_function:
@@ -2518,18 +2520,17 @@ class CFGBase(Analysis):
2518
2520
  #
2519
2521
 
2520
2522
  @staticmethod
2521
- def _is_noop_block(arch: archinfo.Arch, block):
2523
+ def _is_noop_block(arch: archinfo.Arch, block) -> bool:
2522
2524
  """
2523
2525
  Check if the block is a no-op block by checking VEX statements.
2524
2526
 
2525
2527
  :param arch: An architecture descriptor.
2526
2528
  :param block: The VEX block instance.
2527
2529
  :return: True if the entire block is a single-byte or multi-byte nop instruction, False otherwise.
2528
- :rtype: bool
2529
2530
  """
2530
2531
 
2531
2532
  if arch.name == "X86" or arch.name == "AMD64":
2532
- if set(block.bytes) == {"b\x90"}:
2533
+ if set(block.bytes) == {0x90}:
2533
2534
  return True
2534
2535
  elif arch.name == "MIPS32":
2535
2536
  if arch.memory_endness == "Iend_BE":
@@ -2575,36 +2576,7 @@ class CFGBase(Analysis):
2575
2576
  if THUMB_NOOPS.issuperset(insns):
2576
2577
  return True
2577
2578
 
2578
- # Fallback
2579
- # the block is a noop block if it only has IMark statements **and** it jumps to its immediate successor. VEX
2580
- # will generate such blocks when opt_level==1 and cross_insn_opt is True
2581
- fallthrough_addr = block.addr + block.size
2582
- next_ = block.vex.next
2583
- if (
2584
- isinstance(next_, pyvex.IRExpr.Const)
2585
- and next_.con.value == fallthrough_addr
2586
- and all((type(stmt) is pyvex.IRStmt.IMark) for stmt in block.vex.statements)
2587
- ):
2588
- return True
2589
-
2590
- # the block is a noop block if it only has IMark statements and IP-setting statements that set the IP to the
2591
- # next location. VEX will generate such blocks when opt_level==1 and cross_insn_opt is False
2592
- ip_offset = arch.ip_offset
2593
- if (
2594
- all(
2595
- (type(stmt) is pyvex.IRStmt.IMark or (type(stmt) is pyvex.IRStmt.Put and stmt.offset == ip_offset))
2596
- for stmt in block.vex.statements
2597
- )
2598
- and block.vex.statements
2599
- ):
2600
- last_stmt = block.vex.statements[-1]
2601
- if (
2602
- isinstance(last_stmt, pyvex.IRStmt.IMark)
2603
- and isinstance(next_, pyvex.IRExpr.Const)
2604
- and next_.con.value == fallthrough_addr
2605
- ):
2606
- return True
2607
- return False
2579
+ return block.vex_nostmt.is_noop_block
2608
2580
 
2609
2581
  @staticmethod
2610
2582
  def _is_noop_insn(insn):
@@ -2083,7 +2083,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
2083
2083
  if src_node_key is None:
2084
2084
  if dst_node is None:
2085
2085
  raise ValueError("Either src_node_key or dst_node_key must be specified.")
2086
- self.kb.functions.function(dst_node.function_address, create=True)._register_nodes(True, dst_codenode)
2086
+ self.kb.functions.function(dst_node.function_address, create=True)._register_node(True, dst_codenode)
2087
2087
  return
2088
2088
 
2089
2089
  src_node = self._graph_get_node(src_node_key, terminator_for_nonexistent_node=True)
@@ -3208,109 +3208,6 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
3208
3208
  # Update loop backedges and graph
3209
3209
  self._loop_back_edges = list(itertools.chain.from_iterable(loop.continue_edges for loop in loop_finder.loops))
3210
3210
 
3211
- # Private methods - function/procedure/subroutine analysis
3212
- # Including calling convention, function arguments, etc.
3213
-
3214
- def _refine_function_arguments(self, func, callsites):
3215
- """
3216
-
3217
- :param func:
3218
- :param callsites:
3219
- :return:
3220
- """
3221
-
3222
- for i, c in enumerate(callsites):
3223
- # Execute one block ahead of the callsite, and execute one basic block after the callsite
3224
- # In this process, the following tasks are performed:
3225
- # - Record registers/stack variables that are modified
3226
- # - Record the change of the stack pointer
3227
- # - Check if the return value is used immediately
3228
- # We assume that the stack is balanced before and after the call (you can have caller clean-up of course).
3229
- # Any abnormal behaviors will be logged.
3230
- # Hopefully this approach will allow us to have a better understanding of parameters of those function
3231
- # stubs and function proxies.
3232
-
3233
- if c.simprocedure_name is not None:
3234
- # Skip all SimProcedures
3235
- continue
3236
-
3237
- l.debug("Refining %s at 0x%x (%d/%d).", repr(func), c.addr, i, len(callsites))
3238
-
3239
- # Get a basic block ahead of the callsite
3240
- blocks_ahead = [c]
3241
-
3242
- # the block after
3243
- blocks_after = []
3244
- successors = self.get_successors_and_jumpkind(c, excluding_fakeret=False)
3245
- for s, jk in successors:
3246
- if jk == "Ijk_FakeRet":
3247
- blocks_after = [s]
3248
- break
3249
-
3250
- regs_overwritten = set()
3251
- stack_overwritten = set()
3252
- regs_read = set()
3253
- regs_written = set()
3254
-
3255
- try:
3256
- # Execute the predecessor
3257
- path = self.project.factory.path(
3258
- self.project.factory.blank_state(mode="fastpath", addr=blocks_ahead[0].addr)
3259
- )
3260
- path.step()
3261
- all_successors = path.next_run.successors + path.next_run.unsat_successors
3262
- if not all_successors:
3263
- continue
3264
-
3265
- suc = all_successors[0]
3266
- se = suc.solver
3267
- # Examine the path log
3268
- actions = suc.history.recent_actions
3269
- sp = se.eval_one(suc.regs.sp, default=0) + self.project.arch.call_sp_fix
3270
- for ac in actions:
3271
- if ac.type == "reg" and ac.action == "write":
3272
- regs_overwritten.add(ac.offset)
3273
- elif ac.type == "mem" and ac.action == "write":
3274
- addr = se.eval_one(ac.addr.ast, default=0)
3275
- if (self.project.arch.call_pushes_ret and addr >= sp + self.project.arch.bytes) or (
3276
- not self.project.arch.call_pushes_ret and addr >= sp
3277
- ):
3278
- offset = addr - sp
3279
- stack_overwritten.add(offset)
3280
-
3281
- func.prepared_registers.add(tuple(regs_overwritten))
3282
- func.prepared_stack_variables.add(tuple(stack_overwritten))
3283
-
3284
- except (SimError, AngrError):
3285
- pass
3286
-
3287
- try:
3288
- if blocks_after:
3289
- path = self.project.factory.path(
3290
- self.project.factory.blank_state(mode="fastpath", addr=blocks_after[0].addr)
3291
- )
3292
- path.step()
3293
- all_successors = path.next_run.successors + path.next_run.unsat_successors
3294
- if not all_successors:
3295
- continue
3296
-
3297
- suc = all_successors[0]
3298
- actions = suc.history.recent_actions
3299
- for ac in actions:
3300
- if ac.type == "reg" and ac.action == "read" and ac.offset not in regs_written:
3301
- regs_read.add(ac.offset)
3302
- elif ac.type == "reg" and ac.action == "write":
3303
- regs_written.add(ac.offset)
3304
-
3305
- # Filter registers, remove unnecessary registers from the set
3306
- # regs_overwritten = self.project.arch.argument_registers.intersection(regs_overwritten)
3307
- regs_read = self.project.arch.argument_registers.intersection(regs_read)
3308
-
3309
- func.registers_read_afterwards.add(tuple(regs_read))
3310
-
3311
- except (SimError, AngrError):
3312
- pass
3313
-
3314
3211
  # Private methods - dominators and post-dominators
3315
3212
 
3316
3213
  def _immediate_dominators(self, node, target_graph=None, reverse_graph=False):