angr 9.2.147__py3-none-manylinux2014_aarch64.whl → 9.2.149__py3-none-manylinux2014_aarch64.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 (90) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/analysis.py +3 -11
  3. angr/analyses/calling_convention/calling_convention.py +42 -2
  4. angr/analyses/calling_convention/fact_collector.py +5 -4
  5. angr/analyses/calling_convention/utils.py +1 -0
  6. angr/analyses/cfg/cfg_base.py +3 -59
  7. angr/analyses/cfg/cfg_emulated.py +17 -14
  8. angr/analyses/cfg/cfg_fast.py +68 -63
  9. angr/analyses/cfg/cfg_fast_soot.py +3 -3
  10. angr/analyses/decompiler/ail_simplifier.py +65 -32
  11. angr/analyses/decompiler/block_simplifier.py +20 -6
  12. angr/analyses/decompiler/callsite_maker.py +28 -18
  13. angr/analyses/decompiler/clinic.py +84 -17
  14. angr/analyses/decompiler/condition_processor.py +0 -21
  15. angr/analyses/decompiler/counters/call_counter.py +3 -0
  16. angr/analyses/decompiler/dephication/rewriting_engine.py +24 -2
  17. angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
  18. angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +15 -13
  19. angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +1 -1
  20. angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
  21. angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +165 -0
  22. angr/analyses/decompiler/optimization_passes/engine_base.py +11 -2
  23. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +17 -2
  24. angr/analyses/decompiler/optimization_passes/optimization_pass.py +10 -6
  25. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +99 -30
  26. angr/analyses/decompiler/peephole_optimizations/__init__.py +6 -0
  27. angr/analyses/decompiler/peephole_optimizations/base.py +43 -3
  28. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
  29. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +3 -0
  30. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +4 -1
  31. angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
  32. angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +69 -2
  33. angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +14 -0
  34. angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
  35. angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
  36. angr/analyses/decompiler/presets/fast.py +2 -0
  37. angr/analyses/decompiler/presets/full.py +2 -0
  38. angr/analyses/decompiler/ssailification/rewriting_engine.py +51 -4
  39. angr/analyses/decompiler/ssailification/ssailification.py +23 -3
  40. angr/analyses/decompiler/ssailification/traversal_engine.py +15 -1
  41. angr/analyses/decompiler/structured_codegen/c.py +146 -15
  42. angr/analyses/decompiler/structuring/phoenix.py +11 -3
  43. angr/analyses/decompiler/utils.py +6 -1
  44. angr/analyses/deobfuscator/api_obf_finder.py +5 -1
  45. angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
  46. angr/analyses/forward_analysis/visitors/graph.py +0 -8
  47. angr/analyses/identifier/runner.py +1 -1
  48. angr/analyses/reaching_definitions/function_handler.py +4 -4
  49. angr/analyses/reassembler.py +1 -1
  50. angr/analyses/s_reaching_definitions/s_rda_view.py +1 -0
  51. angr/analyses/stack_pointer_tracker.py +1 -1
  52. angr/analyses/static_hooker.py +11 -9
  53. angr/analyses/typehoon/lifter.py +20 -0
  54. angr/analyses/typehoon/simple_solver.py +42 -9
  55. angr/analyses/typehoon/translator.py +4 -1
  56. angr/analyses/typehoon/typeconsts.py +17 -6
  57. angr/analyses/typehoon/typehoon.py +21 -5
  58. angr/analyses/variable_recovery/engine_ail.py +52 -13
  59. angr/analyses/variable_recovery/engine_base.py +37 -12
  60. angr/analyses/variable_recovery/variable_recovery_fast.py +33 -2
  61. angr/calling_conventions.py +96 -27
  62. angr/engines/light/engine.py +7 -0
  63. angr/exploration_techniques/director.py +1 -1
  64. angr/knowledge_plugins/functions/function.py +109 -38
  65. angr/knowledge_plugins/functions/function_manager.py +9 -0
  66. angr/knowledge_plugins/functions/function_parser.py +9 -1
  67. angr/knowledge_plugins/functions/soot_function.py +1 -1
  68. angr/knowledge_plugins/key_definitions/key_definition_manager.py +1 -1
  69. angr/knowledge_plugins/propagations/states.py +5 -2
  70. angr/knowledge_plugins/variables/variable_manager.py +3 -3
  71. angr/procedures/definitions/__init__.py +15 -12
  72. angr/procedures/definitions/types_stl.py +22 -0
  73. angr/procedures/stubs/format_parser.py +1 -1
  74. angr/project.py +23 -29
  75. angr/protos/cfg_pb2.py +14 -25
  76. angr/protos/function_pb2.py +11 -22
  77. angr/protos/primitives_pb2.py +36 -47
  78. angr/protos/variables_pb2.py +28 -39
  79. angr/protos/xrefs_pb2.py +8 -19
  80. angr/sim_type.py +251 -146
  81. angr/simos/cgc.py +1 -1
  82. angr/simos/linux.py +5 -5
  83. angr/simos/windows.py +5 -5
  84. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -1
  85. {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/METADATA +9 -8
  86. {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/RECORD +90 -84
  87. {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/WHEEL +1 -1
  88. {angr-9.2.147.dist-info → angr-9.2.149.dist-info/licenses}/LICENSE +3 -0
  89. {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/entry_points.txt +0 -0
  90. {angr-9.2.147.dist-info → angr-9.2.149.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.147"
5
+ __version__ = "9.2.149"
6
6
 
7
7
  if bytes is str:
8
8
  raise Exception(
angr/analyses/analysis.py CHANGED
@@ -18,7 +18,6 @@ import typing
18
18
  from rich import progress
19
19
 
20
20
  from angr.misc.plugins import PluginVendor, VendorPreset
21
- from angr.misc.ux import deprecated
22
21
  from angr.misc import telemetry
23
22
  from angr.misc.testing import is_testing
24
23
 
@@ -121,10 +120,6 @@ class AnalysesHub(PluginVendor[A]):
121
120
  super().__init__()
122
121
  self.project = project
123
122
 
124
- @deprecated()
125
- def reload_analyses(self): # pylint: disable=no-self-use
126
- return
127
-
128
123
  def _init_plugin(self, plugin_cls: type[A]) -> AnalysisFactory[A]:
129
124
  return AnalysisFactory(self.project, plugin_cls)
130
125
 
@@ -392,12 +387,9 @@ class Analysis:
392
387
 
393
388
  def __getstate__(self):
394
389
  d = dict(self.__dict__)
395
- if "_progressbar" in d:
396
- del d["_progressbar"]
397
- if "_progress_callback" in d:
398
- del d["_progress_callback"]
399
- if "_statusbar" in d:
400
- del d["_statusbar"]
390
+ d.pop("_progressbar", None)
391
+ d.pop("_progress_callback", None)
392
+ d.pop("_statusbar", None)
401
393
  return d
402
394
 
403
395
  def __setstate__(self, state):
@@ -13,8 +13,16 @@ import ailment
13
13
 
14
14
  from angr.code_location import ExternalCodeLocation
15
15
 
16
- from angr.calling_conventions import SimFunctionArgument, SimRegArg, SimStackArg, SimCC, default_cc
16
+ from angr.calling_conventions import (
17
+ SimFunctionArgument,
18
+ SimRegArg,
19
+ SimStackArg,
20
+ SimCC,
21
+ default_cc,
22
+ SimCCMicrosoftThiscall,
23
+ )
17
24
  from angr.sim_type import (
25
+ SimTypeCppFunction,
18
26
  SimTypeInt,
19
27
  SimTypeFunction,
20
28
  SimType,
@@ -24,6 +32,7 @@ from angr.sim_type import (
24
32
  SimTypeBottom,
25
33
  SimTypeFloat,
26
34
  SimTypeDouble,
35
+ parse_cpp_file,
27
36
  )
28
37
  from angr.sim_variable import SimStackVariable, SimRegisterVariable
29
38
  from angr.knowledge_plugins.key_definitions.atoms import Register, MemoryLocation, SpOffset
@@ -153,6 +162,13 @@ class CallingConventionAnalysis(Analysis):
153
162
 
154
163
  assert self._function is not None
155
164
 
165
+ demangled_name = self._function.demangled_name
166
+ if demangled_name != self._function.name:
167
+ r_demangled = self._analyze_demangled_name(demangled_name)
168
+ if r_demangled is not None:
169
+ self.cc, self.prototype, self.prototype_libname = r_demangled
170
+ return
171
+
156
172
  if self._function.is_simprocedure:
157
173
  hooker = self.project.hooked_by(self._function.addr)
158
174
  if isinstance(
@@ -348,6 +364,30 @@ class CallingConventionAnalysis(Analysis):
348
364
 
349
365
  return None
350
366
 
367
+ def _analyze_demangled_name(self, name: str) -> tuple[SimCC, SimTypeFunction, str | None] | None:
368
+ """
369
+ Analyze a function with a demangled name. Only C++ names are supported for now.
370
+
371
+ :param name: The demangled name of the function.
372
+ :return: A tuple of the calling convention, the function type, and the library name if available.
373
+ """
374
+ parsed, _ = parse_cpp_file(name)
375
+ if not parsed or len(parsed) != 1:
376
+ return None
377
+ proto = next(iter(parsed.values()))
378
+ if (
379
+ isinstance(proto, SimTypeCppFunction)
380
+ and self.project.simos.name == "Win32"
381
+ and self.project.arch.name == "X86"
382
+ and proto.convention == "__thiscall"
383
+ ):
384
+ cc_cls = SimCCMicrosoftThiscall
385
+ else:
386
+ cc_cls = default_cc(self.project.arch.name, self.project.simos.name)
387
+ assert cc_cls is not None
388
+ cc = cc_cls(self.project.arch)
389
+ return cc, proto, None
390
+
351
391
  def _analyze_function(self) -> tuple[SimCC, SimTypeFunction] | None:
352
392
  """
353
393
  Go over the variable information in variable manager for this function, and return all uninitialized
@@ -681,7 +721,7 @@ class CallingConventionAnalysis(Analysis):
681
721
  # no more arguments
682
722
  temp_args.append(None)
683
723
  elif isinstance(arg_loc, SimStackArg):
684
- if arg_loc.stack_offset in defs_by_stack_offset:
724
+ if arg_loc.stack_offset - cc.STACKARG_SP_DIFF in defs_by_stack_offset:
685
725
  temp_args.append(arg_loc)
686
726
  else:
687
727
  # no more arguments
@@ -445,10 +445,11 @@ class FactCollector(Analysis):
445
445
  if func_succ.prototype_libname is not None:
446
446
  # we need to deref the prototype in case it uses SimTypeRef internally
447
447
  type_collections = []
448
- prototype_lib = SIM_LIBRARIES[func_succ.prototype_libname]
449
- if prototype_lib.type_collection_names:
450
- for typelib_name in prototype_lib.type_collection_names:
451
- type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
448
+ for prototype_lib in SIM_LIBRARIES[func_succ.prototype_libname]:
449
+ if prototype_lib.type_collection_names:
450
+ for typelib_name in prototype_lib.type_collection_names:
451
+ type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
452
+ if type_collections:
452
453
  proto = dereference_simtype(proto, type_collections)
453
454
 
454
455
  assert isinstance(proto, SimTypeFunction) and proto.returnty is not None
@@ -35,6 +35,7 @@ def is_sane_register_variable(
35
35
  return 16 <= reg_offset < 80 # x0-x7
36
36
 
37
37
  if arch_name == "AMD64":
38
+ # TODO is rbx ever a register?
38
39
  return 24 <= reg_offset < 40 or 64 <= reg_offset < 104 # rcx, rdx # rsi, rdi, r8, r9, r10
39
40
  # 224 <= reg_offset < 480) # xmm0-xmm7
40
41
 
@@ -17,7 +17,6 @@ from archinfo.arch_arm import is_arm_arch, get_real_address_if_arm
17
17
  from angr.knowledge_plugins.functions.function_manager import FunctionManager
18
18
  from angr.knowledge_plugins.functions.function import Function
19
19
  from angr.knowledge_plugins.cfg import IndirectJump, CFGNode, CFGENode, CFGModel # pylint:disable=unused-import
20
- from angr.misc.ux import deprecated
21
20
  from angr.procedures.stubs.UnresolvableJumpTarget import UnresolvableJumpTarget
22
21
  from angr.utils.constants import DEFAULT_STATEMENT
23
22
  from angr.procedures.procedure_dict import SIM_PROCEDURES
@@ -354,64 +353,9 @@ class CFGBase(Analysis):
354
353
 
355
354
  raise NotImplementedError("I'm too lazy to implement it right now")
356
355
 
357
- @deprecated(replacement="self.model.get_predecessors()")
358
- def get_predecessors(self, cfgnode, excluding_fakeret=True, jumpkind=None):
359
- return self._model.get_predecessors(cfgnode, excluding_fakeret=excluding_fakeret, jumpkind=jumpkind)
360
-
361
- @deprecated(replacement="self.model.get_successors()")
362
- def get_successors(self, node, excluding_fakeret=True, jumpkind=None):
363
- return self._model.get_successors(node, excluding_fakeret=excluding_fakeret, jumpkind=jumpkind)
364
-
365
- @deprecated(replacement="self.model.get_successors_and_jumpkind")
366
- def get_successors_and_jumpkind(self, node, excluding_fakeret=True):
367
- return self._model.get_successors_and_jumpkind(node, excluding_fakeret=excluding_fakeret)
368
-
369
- @deprecated(replacement="self.model.get_all_predecessors()")
370
- def get_all_predecessors(self, cfgnode, depth_limit=None):
371
- return self._model.get_all_predecessors(cfgnode, depth_limit)
372
-
373
- @deprecated(replacement="self.model.get_all_successors()")
374
- def get_all_successors(self, cfgnode, depth_limit=None):
375
- return self._model.get_all_successors(cfgnode, depth_limit)
376
-
377
- @deprecated(replacement="self.model.get_node()")
378
- def get_node(self, block_id):
379
- return self._model.get_node(block_id)
380
-
381
- @deprecated(replacement="self.model.get_any_node()")
382
- def get_any_node(self, addr, is_syscall=None, anyaddr=False, force_fastpath=False):
383
- return self._model.get_any_node(addr, is_syscall=is_syscall, anyaddr=anyaddr, force_fastpath=force_fastpath)
384
-
385
- @deprecated(replacement="self.model.get_all_nodes()")
386
- def get_all_nodes(self, addr, is_syscall=None, anyaddr=False):
387
- return self._model.get_all_nodes(addr, is_syscall=is_syscall, anyaddr=anyaddr)
388
-
389
- @deprecated(replacement="self.model.nodes()")
390
- def nodes(self):
391
- return self._model.nodes()
392
-
393
- @deprecated(replacement="nodes")
394
- def nodes_iter(self):
395
- """
396
- (Decrepated) An iterator of all nodes in the graph. Will be removed in the future.
397
-
398
- :return: The iterator.
399
- :rtype: iterator
400
- """
401
-
402
- return self.nodes()
403
-
404
356
  def get_loop_back_edges(self):
405
357
  return self._loop_back_edges
406
358
 
407
- @deprecated(replacement="self.model.get_branching_nodes()")
408
- def get_branching_nodes(self):
409
- return self._model.get_branching_nodes()
410
-
411
- @deprecated(replacement="self.model.get_exit_stmt_idx")
412
- def get_exit_stmt_idx(self, src_block, dst_block):
413
- return self._model.get_exit_stmt_idx(src_block, dst_block)
414
-
415
359
  @property
416
360
  def graph(self) -> networkx.DiGraph[CFGNode]:
417
361
  raise NotImplementedError
@@ -1555,7 +1499,7 @@ class CFGBase(Analysis):
1555
1499
  ):
1556
1500
  # all nops. mark this function as a function alignment
1557
1501
  l.debug("Function chunk %#x is probably used as a function alignment (all nops).", func_addr)
1558
- self.kb.functions[func_addr].alignment = True
1502
+ self.kb.functions[func_addr].is_alignment = True
1559
1503
  continue
1560
1504
  node = function.get_node(block.addr)
1561
1505
  assert node is not None
@@ -1563,7 +1507,7 @@ class CFGBase(Analysis):
1563
1507
  if len(successors) == 1 and successors[0].addr == node.addr:
1564
1508
  # self loop. mark this function as a function alignment
1565
1509
  l.debug("Function chunk %#x is probably used as a function alignment (self-loop).", func_addr)
1566
- self.kb.functions[func_addr].alignment = True
1510
+ self.kb.functions[func_addr].is_alignment = True
1567
1511
  continue
1568
1512
 
1569
1513
  def make_functions(self):
@@ -2110,7 +2054,7 @@ class CFGBase(Analysis):
2110
2054
  continue
2111
2055
  if func_addr in jumptable_entries:
2112
2056
  # is there any call edge pointing to it?
2113
- func_node = self.get_any_node(func_addr, force_fastpath=True)
2057
+ func_node = self.model.get_any_node(func_addr, force_fastpath=True)
2114
2058
  if func_node is not None:
2115
2059
  in_edges = self.graph.in_edges(func_node, data=True)
2116
2060
  has_transition_pred = None
@@ -472,7 +472,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
472
472
  src_blocknode: BlockNode = back_edge[0]
473
473
  dst_blocknode: BlockNode = back_edge[1]
474
474
 
475
- for src in self.get_all_nodes(src_blocknode.addr):
475
+ for src in self.model.get_all_nodes(src_blocknode.addr):
476
476
  for dst in graph.successors(src):
477
477
  if dst.addr != dst_blocknode.addr:
478
478
  continue
@@ -524,7 +524,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
524
524
  start = self._starts[0]
525
525
  if isinstance(start, tuple):
526
526
  start, _ = start # pylint: disable=unpacking-non-sequence
527
- start_node = self.get_any_node(start)
527
+ start_node = self.model.get_any_node(start)
528
528
  if start_node is None:
529
529
  raise AngrCFGError("Cannot find start node when trying to unroll loops. The CFG might be empty.")
530
530
 
@@ -720,7 +720,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
720
720
  # FIXME: syscalls are not supported
721
721
  # FIXME: start should also take a CFGNode instance
722
722
 
723
- start_node = self.get_any_node(start)
723
+ start_node = self.model.get_any_node(start)
724
724
  assert start_node is not None
725
725
 
726
726
  node_wrapper = (start_node, 0)
@@ -2286,9 +2286,9 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
2286
2286
  # Remove that edge!
2287
2287
  graph.remove_edge(call_func_addr, return_to_addr)
2288
2288
  # Remove the edge in CFG
2289
- nodes = self.get_all_nodes(callsite_block_addr)
2289
+ nodes = self.model.get_all_nodes(callsite_block_addr)
2290
2290
  for n in nodes:
2291
- successors = self.get_successors_and_jumpkind(n, excluding_fakeret=False)
2291
+ successors = self.model.get_successors_and_jumpkind(n, excluding_fakeret=False)
2292
2292
  for successor, jumpkind in successors:
2293
2293
  if jumpkind == "Ijk_FakeRet" and successor.addr == return_to_addr:
2294
2294
  self.remove_edge(n, successor)
@@ -2548,7 +2548,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
2548
2548
  for start in starts:
2549
2549
  l.debug("Start symbolic execution at 0x%x on program slice.", start)
2550
2550
  # Get the state from our CFG
2551
- node = self.get_any_node(start)
2551
+ node = self.model.get_any_node(start)
2552
2552
  if node is None:
2553
2553
  # Well, we have to live with an empty state
2554
2554
  base_state = self.project.factory.blank_state(addr=start)
@@ -2561,7 +2561,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
2561
2561
  initial_nodes = [n for n in bc.taint_graph.nodes() if bc.taint_graph.in_degree(n) == 0]
2562
2562
  for cl in initial_nodes:
2563
2563
  # Iterate in all actions of this node, and pick corresponding actions
2564
- cfg_nodes = self.get_all_nodes(cl.block_addr)
2564
+ cfg_nodes = self.model.get_all_nodes(cl.block_addr)
2565
2565
  for n in cfg_nodes:
2566
2566
  if not n.final_states:
2567
2567
  continue
@@ -2967,10 +2967,13 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
2967
2967
  new_state.options.add(o.DO_RET_EMULATION)
2968
2968
  # Remove bad constraints
2969
2969
  # FIXME: This is so hackish...
2970
- new_state.solver._solver.constraints = [
2970
+ preserved_constraints = [
2971
2971
  c for c in new_state.solver.constraints if c.op != "BoolV" or c.args[0] is not False
2972
2972
  ]
2973
- new_state.solver._solver._result = None
2973
+ new_solver = new_state.solver._solver.blank_copy()
2974
+ new_solver.add(preserved_constraints)
2975
+ new_state.solver._stored_solver = new_solver
2976
+
2974
2977
  # Swap them
2975
2978
  saved_state, job.state = job.state, new_state
2976
2979
  sim_successors, exception_info, _ = self._get_simsuccessors(addr, job)
@@ -3376,9 +3379,9 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
3376
3379
 
3377
3380
  all_predecessors = []
3378
3381
 
3379
- nodes = self.get_all_nodes(function_address)
3382
+ nodes = self.model.get_all_nodes(function_address)
3380
3383
  for n in nodes:
3381
- predecessors = list(self.get_predecessors(n))
3384
+ predecessors = list(self.model.get_predecessors(n))
3382
3385
  all_predecessors.extend(predecessors)
3383
3386
 
3384
3387
  return all_predecessors
@@ -3391,8 +3394,8 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
3391
3394
  Return: a list of lists of nodes representing paths.
3392
3395
  """
3393
3396
  if isinstance(begin, int) and isinstance(end, int):
3394
- n_begin = self.get_any_node(begin)
3395
- n_end = self.get_any_node(end)
3397
+ n_begin = self.model.get_any_node(begin)
3398
+ n_end = self.model.get_any_node(end)
3396
3399
 
3397
3400
  elif isinstance(begin, CFGENode) and isinstance(end, CFGENode):
3398
3401
  n_begin = begin
@@ -3417,7 +3420,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
3417
3420
 
3418
3421
  for ep in self._entry_points:
3419
3422
  # FIXME: This is not always correct. We'd better store CFGNodes in self._entry_points
3420
- ep_node = self.get_any_node(ep)
3423
+ ep_node = self.model.get_any_node(ep)
3421
3424
 
3422
3425
  if not ep_node:
3423
3426
  continue
@@ -22,10 +22,10 @@ from archinfo.arch_soot import SootAddressDescriptor
22
22
  from archinfo.arch_arm import is_arm_arch, get_real_address_if_arm
23
23
 
24
24
  from angr.analyses import AnalysesHub
25
+ from angr.misc.ux import once
25
26
  from angr.knowledge_plugins.cfg import CFGNode, MemoryDataSort, MemoryData, IndirectJump, IndirectJumpType
26
27
  from angr.knowledge_plugins.xrefs import XRef, XRefType
27
28
  from angr.knowledge_plugins.functions import Function
28
- from angr.misc.ux import deprecated
29
29
  from angr.codenode import HookNode
30
30
  from angr import sim_options as o
31
31
  from angr.errors import (
@@ -589,10 +589,10 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
589
589
  regions=None,
590
590
  pickle_intermediate_results=False,
591
591
  symbols=True,
592
- function_prologues=True,
592
+ function_prologues: bool | None = None,
593
593
  resolve_indirect_jumps=True,
594
594
  force_segment=False,
595
- force_smart_scan=True,
595
+ force_smart_scan: bool | None = None,
596
596
  force_complete_scan=False,
597
597
  indirect_jump_target_limit=100000,
598
598
  data_references=True,
@@ -712,6 +712,20 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
712
712
  if binary is not None and not objects:
713
713
  objects = [binary]
714
714
 
715
+ is_dotnet = (
716
+ isinstance(self.project.loader.main_object, cle.backends.pe.PE)
717
+ and self.project.loader.main_object.is_dotnet
718
+ )
719
+
720
+ if function_prologues is None:
721
+ function_prologues = not is_dotnet
722
+ if is_dotnet and once("dotnet_native"):
723
+ l.warning("You're trying to analyze a .NET binary as native code. Are you sure?")
724
+ if force_smart_scan is None:
725
+ force_smart_scan = not is_dotnet
726
+ if is_dotnet and once("dotnet_native"):
727
+ l.warning("You're trying to analyze a .NET binary as native code. Are you sure?")
728
+
715
729
  CFGBase.__init__(
716
730
  self,
717
731
  "fast",
@@ -2117,6 +2131,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
2117
2131
  src_func = self.functions.function(addr=cfg_job.src_node.addr, create=True)
2118
2132
  else:
2119
2133
  src_func = self.functions.get_by_addr(cfg_job.src_node.addr)
2134
+ assert src_func is not None
2120
2135
  if len(src_func.block_addrs_set) <= 1 and src_func.is_default_name:
2121
2136
  # assign a name to the caller function that jumps to this procedure
2122
2137
  src_func.name = procedure.display_name
@@ -3843,6 +3858,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
3843
3858
 
3844
3859
  for ep in endpoints:
3845
3860
  src = self.model.get_any_node(ep.addr)
3861
+ assert src is not None
3846
3862
  for rt in return_targets:
3847
3863
  if not src.instruction_addrs:
3848
3864
  ins_addr = None
@@ -4333,7 +4349,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
4333
4349
 
4334
4350
  # extra check for ARM
4335
4351
  if is_arm_arch(self.project.arch) and self._seg_list.occupied_by_sort(addr) == "code":
4336
- existing_node = self.get_any_node(addr, anyaddr=True)
4352
+ existing_node = self.model.get_any_node(addr, anyaddr=True)
4337
4353
  if existing_node is not None and (addr & 1) != (existing_node.addr & 1):
4338
4354
  # we are trying to break an existing ARM node with a THUMB node, or vice versa
4339
4355
  # this is probably because our current node is unexpected
@@ -4825,66 +4841,68 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
4825
4841
 
4826
4842
  # determine if the function uses ebp as a general purpose register or not
4827
4843
  if addr == func_addr or 0 < addr - func_addr <= 0x20:
4828
- ebp_as_gpr = True
4829
- cap = self._lift(addr, size=cfg_node.size).capstone
4830
- for insn in cap.insns:
4831
- if (
4832
- insn.mnemonic == "mov"
4833
- and len(insn.operands) == 2
4834
- and insn.operands[0].type == capstone.x86.X86_OP_REG
4835
- and insn.operands[1].type == capstone.x86.X86_OP_REG
4836
- ):
4844
+ func = self.kb.functions.get_by_addr(func_addr)
4845
+ if "bp_as_gpr" not in func.info:
4846
+ ebp_as_gpr = True
4847
+ cap = self._lift(addr, size=cfg_node.size).capstone
4848
+ for insn in cap.insns:
4837
4849
  if (
4850
+ insn.mnemonic == "mov"
4851
+ and len(insn.operands) == 2
4852
+ and insn.operands[0].type == capstone.x86.X86_OP_REG
4853
+ and insn.operands[1].type == capstone.x86.X86_OP_REG
4854
+ ):
4855
+ if (
4856
+ insn.operands[0].reg == capstone.x86.X86_REG_EBP
4857
+ and insn.operands[1].reg == capstone.x86.X86_REG_ESP
4858
+ ):
4859
+ ebp_as_gpr = False
4860
+ break
4861
+ elif (
4862
+ insn.mnemonic == "lea"
4863
+ and len(insn.operands) == 2
4864
+ and insn.operands[0].type == capstone.x86.X86_OP_REG
4865
+ and insn.operands[1].type == capstone.x86.X86_OP_MEM
4866
+ ) and (
4838
4867
  insn.operands[0].reg == capstone.x86.X86_REG_EBP
4839
- and insn.operands[1].reg == capstone.x86.X86_REG_ESP
4868
+ and insn.operands[1].mem.base == capstone.x86.X86_REG_ESP
4840
4869
  ):
4841
4870
  ebp_as_gpr = False
4842
4871
  break
4843
- elif (
4844
- insn.mnemonic == "lea"
4845
- and len(insn.operands) == 2
4846
- and insn.operands[0].type == capstone.x86.X86_OP_REG
4847
- and insn.operands[1].type == capstone.x86.X86_OP_MEM
4848
- ) and (
4849
- insn.operands[0].reg == capstone.x86.X86_REG_EBP
4850
- and insn.operands[1].mem.base == capstone.x86.X86_REG_ESP
4851
- ):
4852
- ebp_as_gpr = False
4853
- break
4854
- func = self.kb.functions.get_by_addr(func_addr)
4855
- func.info["bp_as_gpr"] = ebp_as_gpr
4872
+ func.info["bp_as_gpr"] = ebp_as_gpr
4856
4873
 
4857
4874
  elif self.project.arch.name == "AMD64":
4858
4875
  # determine if the function uses rbp as a general purpose register or not
4859
4876
  if addr == func_addr or 0 < addr - func_addr <= 0x20:
4860
- rbp_as_gpr = True
4861
- cap = self._lift(addr, size=cfg_node.size).capstone
4862
- for insn in cap.insns:
4863
- if (
4864
- insn.mnemonic == "mov"
4865
- and len(insn.operands) == 2
4866
- and insn.operands[0].type == capstone.x86.X86_OP_REG
4867
- and insn.operands[1].type == capstone.x86.X86_OP_REG
4868
- ):
4877
+ func = self.kb.functions.get_by_addr(func_addr)
4878
+ if "bp_as_gpr" not in func.info:
4879
+ rbp_as_gpr = True
4880
+ cap = self._lift(addr, size=cfg_node.size).capstone
4881
+ for insn in cap.insns:
4869
4882
  if (
4883
+ insn.mnemonic == "mov"
4884
+ and len(insn.operands) == 2
4885
+ and insn.operands[0].type == capstone.x86.X86_OP_REG
4886
+ and insn.operands[1].type == capstone.x86.X86_OP_REG
4887
+ ):
4888
+ if (
4889
+ insn.operands[0].reg == capstone.x86.X86_REG_RBP
4890
+ and insn.operands[1].reg == capstone.x86.X86_REG_RSP
4891
+ ):
4892
+ rbp_as_gpr = False
4893
+ break
4894
+ elif (
4895
+ insn.mnemonic == "lea"
4896
+ and len(insn.operands) == 2
4897
+ and insn.operands[0].type == capstone.x86.X86_OP_REG
4898
+ and insn.operands[1].type == capstone.x86.X86_OP_MEM
4899
+ ) and (
4870
4900
  insn.operands[0].reg == capstone.x86.X86_REG_RBP
4871
- and insn.operands[1].reg == capstone.x86.X86_REG_RSP
4901
+ and insn.operands[1].mem.base == capstone.x86.X86_REG_RSP
4872
4902
  ):
4873
4903
  rbp_as_gpr = False
4874
4904
  break
4875
- elif (
4876
- insn.mnemonic == "lea"
4877
- and len(insn.operands) == 2
4878
- and insn.operands[0].type == capstone.x86.X86_OP_REG
4879
- and insn.operands[1].type == capstone.x86.X86_OP_MEM
4880
- ) and (
4881
- insn.operands[0].reg == capstone.x86.X86_REG_RBP
4882
- and insn.operands[1].mem.base == capstone.x86.X86_REG_RSP
4883
- ):
4884
- rbp_as_gpr = False
4885
- break
4886
- func = self.kb.functions.get_by_addr(func_addr)
4887
- func.info["bp_as_gpr"] = rbp_as_gpr
4905
+ func.info["bp_as_gpr"] = rbp_as_gpr
4888
4906
 
4889
4907
  def _extract_node_cluster_by_dependency(self, addr, include_successors=False) -> set[int]:
4890
4908
  to_remove = {addr}
@@ -5212,18 +5230,5 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
5212
5230
  def output(self):
5213
5231
  return f"{self._graph.edges(data=True)}"
5214
5232
 
5215
- @deprecated(replacement="angr.analyses.CFB")
5216
- def generate_code_cover(self):
5217
- """
5218
- Generate a list of all recovered basic blocks.
5219
- """
5220
-
5221
- lst = []
5222
- for cfg_node in self.graph.nodes():
5223
- size = cfg_node.size
5224
- lst.append((cfg_node.addr, size))
5225
-
5226
- return sorted(lst, key=lambda x: x[0])
5227
-
5228
5233
 
5229
5234
  AnalysesHub.register_default("CFGFast", CFGFast)
@@ -487,7 +487,7 @@ class CFGFastSoot(CFGFast):
487
487
  # it might be a jumpout
488
488
  target_func_addr = None
489
489
  if target_addr in self._traced_addresses:
490
- node = self.get_any_node(target_addr)
490
+ node = self.model.get_any_node(target_addr)
491
491
  if node is not None:
492
492
  target_func_addr = node.function_address
493
493
  if target_func_addr is None:
@@ -578,7 +578,7 @@ class CFGFastSoot(CFGFast):
578
578
  if jumpkind == "Ijk_Call" or jumpkind.startswith("Ijk_Sys"):
579
579
  function_nodes.add(dst)
580
580
 
581
- entry_node = self.get_any_node(self._binary.entry)
581
+ entry_node = self.model.get_any_node(self._binary.entry)
582
582
  if entry_node is not None:
583
583
  function_nodes.add(entry_node)
584
584
 
@@ -616,7 +616,7 @@ class CFGFastSoot(CFGFast):
616
616
  secondary_function_nodes = set()
617
617
  # add all function chunks ("functions" that are not called from anywhere)
618
618
  for func_addr in tmp_functions:
619
- node = self.get_any_node(func_addr)
619
+ node = self.model.get_any_node(func_addr)
620
620
  if node is None:
621
621
  continue
622
622
  if node.addr not in blockaddr_to_function: