angr 9.2.147__py3-none-manylinux2014_aarch64.whl → 9.2.148__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 (52) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/analysis.py +3 -11
  3. angr/analyses/calling_convention/fact_collector.py +5 -4
  4. angr/analyses/calling_convention/utils.py +1 -0
  5. angr/analyses/cfg/cfg_base.py +3 -59
  6. angr/analyses/cfg/cfg_emulated.py +12 -12
  7. angr/analyses/cfg/cfg_fast.py +20 -17
  8. angr/analyses/cfg/cfg_fast_soot.py +3 -3
  9. angr/analyses/decompiler/callsite_maker.py +28 -18
  10. angr/analyses/decompiler/clinic.py +4 -4
  11. angr/analyses/decompiler/condition_processor.py +0 -21
  12. angr/analyses/decompiler/counters/call_counter.py +3 -0
  13. angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +1 -1
  14. angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +14 -0
  15. angr/analyses/decompiler/structured_codegen/c.py +5 -5
  16. angr/analyses/decompiler/structuring/phoenix.py +11 -3
  17. angr/analyses/deobfuscator/api_obf_finder.py +5 -1
  18. angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
  19. angr/analyses/forward_analysis/visitors/graph.py +0 -8
  20. angr/analyses/identifier/runner.py +1 -1
  21. angr/analyses/reaching_definitions/function_handler.py +4 -4
  22. angr/analyses/reassembler.py +1 -1
  23. angr/analyses/stack_pointer_tracker.py +1 -1
  24. angr/analyses/static_hooker.py +11 -9
  25. angr/analyses/variable_recovery/engine_ail.py +8 -8
  26. angr/analyses/variable_recovery/engine_base.py +2 -0
  27. angr/calling_conventions.py +74 -23
  28. angr/exploration_techniques/director.py +1 -1
  29. angr/knowledge_plugins/functions/function.py +41 -38
  30. angr/knowledge_plugins/functions/function_manager.py +9 -0
  31. angr/knowledge_plugins/functions/function_parser.py +9 -1
  32. angr/knowledge_plugins/functions/soot_function.py +1 -1
  33. angr/knowledge_plugins/key_definitions/key_definition_manager.py +1 -1
  34. angr/procedures/definitions/__init__.py +14 -11
  35. angr/procedures/stubs/format_parser.py +1 -1
  36. angr/project.py +23 -29
  37. angr/protos/cfg_pb2.py +14 -25
  38. angr/protos/function_pb2.py +11 -22
  39. angr/protos/primitives_pb2.py +36 -47
  40. angr/protos/variables_pb2.py +28 -39
  41. angr/protos/xrefs_pb2.py +8 -19
  42. angr/sim_type.py +0 -16
  43. angr/simos/cgc.py +1 -1
  44. angr/simos/linux.py +5 -5
  45. angr/simos/windows.py +5 -5
  46. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -1
  47. {angr-9.2.147.dist-info → angr-9.2.148.dist-info}/METADATA +8 -7
  48. {angr-9.2.147.dist-info → angr-9.2.148.dist-info}/RECORD +52 -52
  49. {angr-9.2.147.dist-info → angr-9.2.148.dist-info}/WHEEL +1 -1
  50. {angr-9.2.147.dist-info → angr-9.2.148.dist-info}/entry_points.txt +0 -0
  51. {angr-9.2.147.dist-info → angr-9.2.148.dist-info/licenses}/LICENSE +0 -0
  52. {angr-9.2.147.dist-info → angr-9.2.148.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.148"
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):
@@ -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
@@ -3376,9 +3376,9 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
3376
3376
 
3377
3377
  all_predecessors = []
3378
3378
 
3379
- nodes = self.get_all_nodes(function_address)
3379
+ nodes = self.model.get_all_nodes(function_address)
3380
3380
  for n in nodes:
3381
- predecessors = list(self.get_predecessors(n))
3381
+ predecessors = list(self.model.get_predecessors(n))
3382
3382
  all_predecessors.extend(predecessors)
3383
3383
 
3384
3384
  return all_predecessors
@@ -3391,8 +3391,8 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
3391
3391
  Return: a list of lists of nodes representing paths.
3392
3392
  """
3393
3393
  if isinstance(begin, int) and isinstance(end, int):
3394
- n_begin = self.get_any_node(begin)
3395
- n_end = self.get_any_node(end)
3394
+ n_begin = self.model.get_any_node(begin)
3395
+ n_end = self.model.get_any_node(end)
3396
3396
 
3397
3397
  elif isinstance(begin, CFGENode) and isinstance(end, CFGENode):
3398
3398
  n_begin = begin
@@ -3417,7 +3417,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
3417
3417
 
3418
3418
  for ep in self._entry_points:
3419
3419
  # FIXME: This is not always correct. We'd better store CFGNodes in self._entry_points
3420
- ep_node = self.get_any_node(ep)
3420
+ ep_node = self.model.get_any_node(ep)
3421
3421
 
3422
3422
  if not ep_node:
3423
3423
  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
@@ -5212,18 +5228,5 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
5212
5228
  def output(self):
5213
5229
  return f"{self._graph.edges(data=True)}"
5214
5230
 
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
5231
 
5229
5232
  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:
@@ -18,7 +18,7 @@ from angr.sim_type import (
18
18
  SimTypeFunction,
19
19
  SimTypeLongLong,
20
20
  )
21
- from angr.calling_conventions import SimRegArg, SimStackArg, SimCC, SimStructArg, SimComboArg
21
+ from angr.calling_conventions import SimReferenceArgument, SimRegArg, SimStackArg, SimCC, SimStructArg, SimComboArg
22
22
  from angr.knowledge_plugins.key_definitions.constants import OP_BEFORE
23
23
  from angr.analyses import Analysis, register_analysis
24
24
  from angr.analyses.s_reaching_definitions import SRDAView
@@ -111,10 +111,10 @@ class CallSiteMaker(Analysis):
111
111
  prototype_libname = func.prototype_libname
112
112
  type_collections = []
113
113
  if prototype_libname is not None:
114
- prototype_lib = SIM_LIBRARIES[prototype_libname]
115
- if prototype_lib.type_collection_names:
116
- for typelib_name in prototype_lib.type_collection_names:
117
- type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
114
+ for prototype_lib in SIM_LIBRARIES[prototype_libname]:
115
+ if prototype_lib.type_collection_names:
116
+ for typelib_name in prototype_lib.type_collection_names:
117
+ type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
118
118
  if type_collections:
119
119
  prototype = dereference_simtype(prototype, type_collections).with_arch( # type: ignore
120
120
  self.project.arch
@@ -144,17 +144,30 @@ class CallSiteMaker(Analysis):
144
144
  arg_locs = cc.arg_locs(callsite_ty)
145
145
 
146
146
  if arg_locs is not None and cc is not None:
147
- expanded_arg_locs = []
147
+ expanded_arg_locs: list[SimStackArg | SimRegArg | SimReferenceArgument] = []
148
148
  for arg_loc in arg_locs:
149
149
  if isinstance(arg_loc, SimComboArg):
150
150
  # a ComboArg spans across multiple locations (mostly stack but *in theory* can also be spanning
151
151
  # across registers). most importantly, a ComboArg represents one variable, not multiple, but we
152
152
  # have no way to know that until later down the pipeline.
153
153
  expanded_arg_locs += arg_loc.locations
154
- else:
154
+ elif isinstance(arg_loc, (SimRegArg, SimStackArg, SimReferenceArgument)):
155
155
  expanded_arg_locs.append(arg_loc)
156
+ else:
157
+ raise NotImplementedError("Not implemented yet.")
156
158
 
157
159
  for arg_loc in expanded_arg_locs:
160
+ if isinstance(arg_loc, SimReferenceArgument):
161
+ if not isinstance(arg_loc.ptr_loc, (SimRegArg, SimStackArg)):
162
+ raise NotImplementedError("Why would a calling convention produce this?")
163
+ if isinstance(arg_loc.main_loc, SimStructArg):
164
+ dereference_size = arg_loc.main_loc.struct.size // self.project.arch.byte_width
165
+ else:
166
+ dereference_size = arg_loc.main_loc.size
167
+ arg_loc = arg_loc.ptr_loc
168
+ else:
169
+ dereference_size = None
170
+
158
171
  if isinstance(arg_loc, SimRegArg):
159
172
  size = arg_loc.size
160
173
  offset = arg_loc.check_offset(cc.arch)
@@ -202,7 +215,7 @@ class CallSiteMaker(Analysis):
202
215
  vvar_use,
203
216
  **vvar_use.tags,
204
217
  )
205
- args.append(vvar_use)
218
+ arg_expr = vvar_use
206
219
  else:
207
220
  reg = Expr.Register(
208
221
  self._atom_idx(),
@@ -212,20 +225,17 @@ class CallSiteMaker(Analysis):
212
225
  reg_name=arg_loc.reg_name,
213
226
  ins_addr=last_stmt.ins_addr,
214
227
  )
215
- args.append(reg)
228
+ arg_expr = reg
216
229
  elif isinstance(arg_loc, SimStackArg):
217
230
  stack_arg_locs.append(arg_loc)
218
231
  _, the_arg = self._resolve_stack_argument(call_stmt, arg_loc)
219
-
220
- if the_arg is not None:
221
- args.append(the_arg)
222
- else:
223
- args.append(None)
224
- elif isinstance(arg_loc, SimStructArg):
225
- l.warning("SimStructArg is not yet supported")
226
-
232
+ arg_expr = the_arg if the_arg is not None else None
227
233
  else:
228
- raise NotImplementedError("Not implemented yet.")
234
+ assert False, "Unreachable"
235
+
236
+ if arg_expr is not None and dereference_size is not None:
237
+ arg_expr = Expr.Load(self._atom_idx(), arg_expr, dereference_size, endness=archinfo.Endness.BE)
238
+ args.append(arg_expr)
229
239
 
230
240
  # Remove the old call statement
231
241
  new_stmts = self.block.statements[:-1]
@@ -1197,10 +1197,10 @@ class Clinic(Analysis):
1197
1197
  prototype_libname = func.prototype_libname
1198
1198
  type_collections = []
1199
1199
  if prototype_libname is not None:
1200
- prototype_lib = SIM_LIBRARIES[prototype_libname]
1201
- if prototype_lib.type_collection_names:
1202
- for typelib_name in prototype_lib.type_collection_names:
1203
- type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
1200
+ for prototype_lib in SIM_LIBRARIES[prototype_libname]:
1201
+ if prototype_lib.type_collection_names:
1202
+ for typelib_name in prototype_lib.type_collection_names:
1203
+ type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
1204
1204
  if type_collections:
1205
1205
  prototype = dereference_simtype(prototype, type_collections).with_arch( # type: ignore
1206
1206
  self.project.arch
@@ -961,27 +961,6 @@ class ConditionProcessor:
961
961
  sympy_expr = ConditionProcessor.claripy_ast_to_sympy_expr(cond, memo=memo)
962
962
  return ConditionProcessor.sympy_expr_to_claripy_ast(sympy.simplify_logic(sympy_expr, deep=False), memo)
963
963
 
964
- @staticmethod
965
- def simplify_condition_deprecated(cond):
966
- # Z3's simplification may yield weird and unreadable results
967
- # hence we mostly rely on our own simplification. we only use Z3's simplification results when it returns a
968
- # concrete value.
969
- claripy_simplified = claripy.simplify(cond)
970
- if not claripy_simplified.symbolic:
971
- return claripy_simplified
972
-
973
- simplified = ConditionProcessor._fold_double_negations(cond)
974
- cond = simplified if simplified is not None else cond
975
- simplified = ConditionProcessor._revert_short_circuit_conditions(cond)
976
- cond = simplified if simplified is not None else cond
977
- simplified = ConditionProcessor._extract_common_subexpressions(cond)
978
- cond = simplified if simplified is not None else cond
979
- # simplified = ConditionProcessor._remove_redundant_terms(cond)
980
- # cond = simplified if simplified is not None else cond
981
- # in the end, use claripy's simplification to handle really easy cases again
982
- simplified = ConditionProcessor._simplify_trivial_cases(cond)
983
- return simplified if simplified is not None else cond
984
-
985
964
  @staticmethod
986
965
  def _simplify_trivial_cases(cond):
987
966
  if cond.op == "And":
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
  from typing import TYPE_CHECKING
3
3
 
4
4
  from ailment import Block
5
+ from ailment.statement import Label
5
6
  from ailment.block_walker import AILBlockWalkerBase
6
7
 
7
8
  from angr.analyses.decompiler.sequence_walker import SequenceWalker
@@ -37,8 +38,10 @@ class AILCallCounter(SequenceWalker):
37
38
  }
38
39
  super().__init__(handlers)
39
40
  self.calls = 0
41
+ self.non_label_stmts = 0
40
42
 
41
43
  def _handle_Block(self, node: Block, **kwargs): # pylint:disable=unused-argument
42
44
  ctr = AILBlockCallCounter()
43
45
  ctr.walk(node)
44
46
  self.calls += ctr.calls
47
+ self.non_label_stmts += sum(1 for stmt in node.statements if not isinstance(stmt, Label))
@@ -66,7 +66,7 @@ class PairAILBlockWalker:
66
66
  def _handle_call_expr(expr_idx: int, expr: Call, stmt_idx: int, stmt: Statement, block_):
67
67
  walked_objs[Call].add(expr)
68
68
 
69
- _stmt_handlers = {typ: _handle_ail_obj for typ in walked_objs}
69
+ _stmt_handlers = dict.fromkeys(walked_objs, _handle_ail_obj)
70
70
  walker.stmt_handlers = _stmt_handlers
71
71
  walker.expr_handlers[Call] = _handle_call_expr
72
72
 
@@ -164,6 +164,20 @@ class RemoveRedundantConversions(PeepholeOptimizationExprBase):
164
164
  **expr.tags,
165
165
  )
166
166
 
167
+ # simpler cases
168
+ # (A & mask) & mask ==> A & mask
169
+ if (
170
+ expr.op == "And"
171
+ and isinstance(expr.operands[1], Const)
172
+ and isinstance(expr.operands[0], BinaryOp)
173
+ and expr.operands[0].op == "And"
174
+ ):
175
+ inner_op0, inner_op1 = expr.operands[0].operands
176
+ if (isinstance(inner_op0, Const) and inner_op0.value == expr.operands[1].value) or (
177
+ isinstance(inner_op1, Const) and inner_op1.value == expr.operands[1].value
178
+ ):
179
+ return expr.operands[0]
180
+
167
181
  return None
168
182
 
169
183
  @staticmethod
@@ -1281,11 +1281,11 @@ class CFunctionCall(CStatement, CExpression):
1281
1281
  if self.callee_func.prototype_libname is not None:
1282
1282
  # we need to deref the prototype in case it uses SimTypeRef internally
1283
1283
  type_collections = []
1284
- prototype_lib = SIM_LIBRARIES[self.callee_func.prototype_libname]
1285
- if prototype_lib.type_collection_names:
1286
- for typelib_name in prototype_lib.type_collection_names:
1287
- type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
1288
- proto = dereference_simtype(proto, type_collections)
1284
+ for prototype_lib in SIM_LIBRARIES[self.callee_func.prototype_libname]:
1285
+ if prototype_lib.type_collection_names:
1286
+ for typelib_name in prototype_lib.type_collection_names:
1287
+ type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
1288
+ proto = dereference_simtype(proto, type_collections)
1289
1289
  return proto
1290
1290
  returnty = SimTypeInt(signed=False)
1291
1291
  return SimTypeFunction([arg.type for arg in self.args], returnty).with_arch(self.codegen.project.arch)
@@ -90,6 +90,7 @@ class PhoenixStructurer(StructurerBase):
90
90
  parent_region=None,
91
91
  improve_algorithm=False,
92
92
  use_multistmtexprs: MultiStmtExprMode = MultiStmtExprMode.MAX_ONE_CALL,
93
+ multistmtexpr_stmt_threshold: int = 5,
93
94
  **kwargs,
94
95
  ):
95
96
  super().__init__(
@@ -126,6 +127,7 @@ class PhoenixStructurer(StructurerBase):
126
127
  self._edge_virtualization_hints = []
127
128
 
128
129
  self._use_multistmtexprs = use_multistmtexprs
130
+ self._multistmtexpr_stmt_threshold = multistmtexpr_stmt_threshold
129
131
  self._analyze()
130
132
 
131
133
  @staticmethod
@@ -540,7 +542,11 @@ class PhoenixStructurer(StructurerBase):
540
542
  ):
541
543
  stmts = self._build_multistatementexpr_statements(succ)
542
544
  assert stmts is not None
543
- if stmts:
545
+ if (
546
+ stmts
547
+ and sum(1 for stmt in stmts if not isinstance(stmt, Label))
548
+ <= self._multistmtexpr_stmt_threshold
549
+ ):
544
550
  edge_cond_succhead = MultiStatementExpression(
545
551
  None,
546
552
  stmts,
@@ -2612,12 +2618,14 @@ class PhoenixStructurer(StructurerBase):
2612
2618
  if self._use_multistmtexprs == MultiStmtExprMode.NEVER:
2613
2619
  return False
2614
2620
  if self._use_multistmtexprs == MultiStmtExprMode.ALWAYS:
2615
- return True
2621
+ ctr = AILCallCounter()
2622
+ ctr.walk(node)
2623
+ return ctr.non_label_stmts <= self._multistmtexpr_stmt_threshold
2616
2624
  if self._use_multistmtexprs == MultiStmtExprMode.MAX_ONE_CALL:
2617
2625
  # count the number of calls
2618
2626
  ctr = AILCallCounter()
2619
2627
  ctr.walk(node)
2620
- return ctr.calls <= 1
2628
+ return ctr.calls <= 1 and ctr.non_label_stmts <= self._multistmtexpr_stmt_threshold
2621
2629
  l.warning("Unsupported enum value for _use_multistmtexprs: %s", self._use_multistmtexprs)
2622
2630
  return False
2623
2631
 
@@ -315,7 +315,11 @@ class APIObfuscationFinder(Analysis):
315
315
 
316
316
  @staticmethod
317
317
  def is_apiname(name: str) -> bool:
318
- return any(not isinstance(lib, SimSyscallLibrary) and lib.has_prototype(name) for lib in SIM_LIBRARIES.values())
318
+ return any(
319
+ not isinstance(lib, SimSyscallLibrary) and lib.has_prototype(name)
320
+ for libs in SIM_LIBRARIES.values()
321
+ for lib in libs
322
+ )
319
323
 
320
324
 
321
325
  AnalysesHub.register_default("APIObfuscationFinder", APIObfuscationFinder)
@@ -30,7 +30,7 @@ class APIObfType1PeepholeOptimizer(PeepholeOptimizationExprBase):
30
30
  # assign a new function on-demand
31
31
  symbol = self.project.loader.extern_object.make_extern(funcname)
32
32
  hook_addr = self.project.hook_symbol(
33
- symbol.rebased_addr, SIM_LIBRARIES["linux"].get_stub(funcname, self.project.arch)
33
+ symbol.rebased_addr, SIM_LIBRARIES["linux"][0].get_stub(funcname, self.project.arch)
34
34
  )
35
35
  func = self.kb.functions.function(addr=hook_addr, name=funcname, create=True)
36
36
  func.is_simprocedure = True