angr 9.2.152__py3-none-manylinux2014_aarch64.whl → 9.2.153__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.

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.152"
5
+ __version__ = "9.2.153"
6
6
 
7
7
  if bytes is str:
8
8
  raise Exception(
@@ -1515,7 +1515,7 @@ class CFGBase(Analysis):
1515
1515
  Revisit the entire control flow graph, create Function instances accordingly, and correctly put blocks into
1516
1516
  each function.
1517
1517
 
1518
- Although Function objects are crated during the CFG recovery, they are neither sound nor accurate. With a
1518
+ Although Function objects are created during the CFG recovery, they are neither sound nor accurate. With a
1519
1519
  pre-constructed CFG, this method rebuilds all functions bearing the following rules:
1520
1520
 
1521
1521
  - A block may only belong to one function.
@@ -1554,6 +1554,45 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
1554
1554
  }:
1555
1555
  func.info["is_alloca_probe"] = True
1556
1556
 
1557
+ # determine if the function is _guard_xfg_dispatch_icall_nop or _guard_xfg_dispatch_icall_fptr
1558
+ if func is not None and not func.is_simprocedure and len(func.block_addrs_set) in {1, 2}:
1559
+ # _guard_xfg_dispatch_icall_nop jumps to _guard_xfg_dispatch_icall_fptr, but we may or may not identify
1560
+ # _guard_xfg_dispatch_icall_fptr as a separate function.
1561
+ # so, two possibilities:
1562
+ # - _guard_xfg_dispatch_icall_nop is a function with one block and jumps to
1563
+ # _guard_xfg_dispatch_icall_fptr.
1564
+ # - _guard_xfg_dispatch_icall_nop is a function with 2 blocks, and the second block is the body of
1565
+ # _guard_xfg_dispatch_icall_fptr.
1566
+ try:
1567
+ block = func.get_block(func.addr)
1568
+ except SimTranslationError:
1569
+ block = None
1570
+ if block is not None and block.instructions == 1:
1571
+ insn = block.capstone.insns[0]
1572
+ if block.bytes == b"\xff\xe0":
1573
+ func.info["jmp_rax"] = True
1574
+ elif (
1575
+ insn.mnemonic == "jmp"
1576
+ and insn.operands[0].type == capstone.x86.X86_OP_MEM
1577
+ and insn.operands[0].mem.base == capstone.x86.X86_REG_RIP
1578
+ and insn.operands[0].mem.disp > 0
1579
+ and insn.operands[0].mem.index == 0
1580
+ ):
1581
+ # where is it jumping to?
1582
+ jumpout_targets = list(self.graph.successors(self.model.get_any_node(func.addr)))
1583
+ if len(jumpout_targets) == 1:
1584
+ jumpout_target = jumpout_targets[0].addr
1585
+ if len(func.block_addrs_set) == 1 and len(func.jumpout_sites) == 1:
1586
+ if (
1587
+ self.kb.functions.contains_addr(jumpout_target)
1588
+ and self.kb.functions.get_by_addr(jumpout_target).get_block(jumpout_target).bytes
1589
+ == b"\xff\xe0"
1590
+ ):
1591
+ func.info["jmp_rax"] = True
1592
+ elif len(func.block_addrs_set) == 2 and func.get_block(jumpout_target).bytes == b"\xff\xe0":
1593
+ # check the second block and ensure it's jmp rax
1594
+ func.info["jmp_rax"] = True
1595
+
1557
1596
  elif self.project.arch.name == "X86":
1558
1597
  # determine if the function is __alloca_probe
1559
1598
  func = self.kb.functions.get_by_addr(func_addr) if self.kb.functions.contains_addr(func_addr) else None
@@ -203,7 +203,6 @@ class AILSimplifier(Analysis):
203
203
  AILGraphWalker(self.func_graph, _handler, replace_nodes=True).walk()
204
204
  self.blocks = {}
205
205
 
206
- @timethis
207
206
  def _compute_reaching_definitions(self) -> SRDAModel:
208
207
  # Computing reaching definitions or return the cached one
209
208
  if self._reaching_definitions is not None:
@@ -485,6 +485,8 @@ class Clinic(Analysis):
485
485
 
486
486
  # duplicate orphaned conditional jump blocks
487
487
  ail_graph = self._duplicate_orphaned_cond_jumps(ail_graph)
488
+ # rewrite jmp_rax function calls
489
+ ail_graph = self._rewrite_jump_rax_calls(ail_graph)
488
490
 
489
491
  # Transform the graph into partial SSA form
490
492
  self._update_progress(35.0, text="Transforming to partial-SSA form")
@@ -930,7 +932,7 @@ class Clinic(Analysis):
930
932
  self.kb.callsite_prototypes.set_prototype(callsite.addr, cc.cc, cc.prototype, manual=False)
931
933
  if func_graph is not None and cc.prototype.returnty is not None:
932
934
  # patch the AIL call statement if we can find one
933
- callsite_ail_block: ailment.Block = next(
935
+ callsite_ail_block: ailment.Block | None = next(
934
936
  iter(bb for bb in func_graph if bb.addr == callsite.addr), None
935
937
  )
936
938
  if callsite_ail_block is not None and callsite_ail_block.statements:
@@ -1005,6 +1007,7 @@ class Clinic(Analysis):
1005
1007
  :return: None
1006
1008
  """
1007
1009
  assert self._func_graph is not None
1010
+ assert self._blocks_by_addr_and_size is not None
1008
1011
 
1009
1012
  for block_node in self._func_graph.nodes():
1010
1013
  ail_block = self._convert(block_node)
@@ -2178,6 +2181,47 @@ class Clinic(Analysis):
2178
2181
 
2179
2182
  return ail_graph
2180
2183
 
2184
+ def _rewrite_jump_rax_calls(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
2185
+ """
2186
+ Rewrite calls to special functions (e.g., guard_dispatch_icall_nop) into `call rax`.
2187
+ """
2188
+
2189
+ if self.project.arch.name != "AMD64":
2190
+ return ail_graph
2191
+ if self._cfg is None:
2192
+ return ail_graph
2193
+
2194
+ for block in ail_graph:
2195
+ if not block.statements:
2196
+ continue
2197
+ assert block.addr is not None
2198
+ last_stmt = block.statements[-1]
2199
+ if isinstance(last_stmt, ailment.Stmt.Call):
2200
+ # we can't examine the call target at this point because constant propagation hasn't run yet; we consult
2201
+ # the CFG instead
2202
+ callsite_node = self._cfg.get_any_node(block.addr, anyaddr=True)
2203
+ if callsite_node is None:
2204
+ break
2205
+ callees = self._cfg.get_successors(callsite_node, jumpkind="Ijk_Call")
2206
+ if len(callees) != 1:
2207
+ break
2208
+ callee = callees[0].addr
2209
+ if self.kb.functions.contains_addr(callee):
2210
+ callee_func = self.kb.functions.get_by_addr(callee)
2211
+ if callee_func.info.get("jmp_rax", False) is True:
2212
+ # rewrite this statement into Call(rax)
2213
+ call_stmt = last_stmt.copy()
2214
+ call_stmt.target = ailment.Expr.Register(
2215
+ self._ail_manager.next_atom(),
2216
+ None,
2217
+ self.project.arch.registers["rax"][0],
2218
+ 64,
2219
+ ins_addr=call_stmt.ins_addr,
2220
+ )
2221
+ block.statements[-1] = call_stmt
2222
+
2223
+ return ail_graph
2224
+
2181
2225
  def _rewrite_ite_expressions(self, ail_graph):
2182
2226
  cfg = self._cfg
2183
2227
  for block in list(ail_graph):
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+ from typing import Any
2
3
  from itertools import count
3
4
  from collections import defaultdict
4
5
  import logging
@@ -70,6 +71,9 @@ class RegionIdentifier(Analysis):
70
71
  self._largest_successor_tree_outside_loop = largest_successor_tree_outside_loop
71
72
  self._force_loop_single_exit = force_loop_single_exit
72
73
  self._complete_successors = complete_successors
74
+ # we keep a dictionary of node and their traversal order in a quasi-topological traversal and update this
75
+ # dictionary as we update the graph
76
+ self._node_order: dict[Any, tuple[int, int]] = {}
73
77
 
74
78
  self._analyze()
75
79
 
@@ -102,11 +106,30 @@ class RegionIdentifier(Analysis):
102
106
 
103
107
  self._start_node = self._get_start_node(graph)
104
108
 
109
+ self._node_order = self._compute_node_order(graph)
110
+
105
111
  self.region = self._make_regions(graph)
106
112
 
107
113
  # make regions into block address lists
108
114
  self.regions_by_block_addrs = self._make_regions_by_block_addrs()
109
115
 
116
+ @staticmethod
117
+ def _compute_node_order(graph: networkx.DiGraph) -> dict[Any, tuple[int, int]]:
118
+ sorted_nodes = GraphUtils.quasi_topological_sort_nodes(graph)
119
+ node_order = {}
120
+ for i, n in enumerate(sorted_nodes):
121
+ node_order[n] = i, 0
122
+ return node_order
123
+
124
+ def _sort_nodes(self, nodes: list | set) -> list:
125
+ """
126
+ Sorts the nodes in the order specified in self._node_order.
127
+
128
+ :param nodes: A list or set of nodes to be sorted.
129
+ :return: A sorted list of nodes.
130
+ """
131
+ return sorted(nodes, key=lambda n: self._node_order[n])
132
+
110
133
  def _make_regions_by_block_addrs(self) -> list[list[tuple[int, int | None]]]:
111
134
  """
112
135
  Creates a list of addr lists representing each region without recursion. A single region is defined
@@ -182,30 +205,6 @@ class RegionIdentifier(Analysis):
182
205
  None,
183
206
  )
184
207
 
185
- def _test_reducibility(self):
186
- # make a copy of the graph
187
- graph = networkx.DiGraph(self._graph)
188
-
189
- # preprocess: make it a super graph
190
- self._make_supergraph(graph)
191
-
192
- while True:
193
- changed = False
194
-
195
- # find a node with a back-edge, remove the edge (deleting the loop), and replace it with a MultiNode
196
- changed |= self._remove_self_loop(graph)
197
-
198
- # find a node that has only one predecessor, and merge it with its predecessor (replace them with a
199
- # MultiNode)
200
- changed |= self._merge_single_entry_node(graph)
201
-
202
- if not changed:
203
- # a fixed-point is reached
204
- break
205
-
206
- # Flow graph reducibility, Hecht and Ullman
207
- return len(graph.nodes) == 1
208
-
209
208
  def _make_supergraph(self, graph: networkx.DiGraph):
210
209
 
211
210
  entry_node = None
@@ -236,7 +235,7 @@ class RegionIdentifier(Analysis):
236
235
 
237
236
  def _find_loop_headers(self, graph: networkx.DiGraph) -> list:
238
237
  heads = list({t for _, t in dfs_back_edges(graph, self._start_node)})
239
- return GraphUtils.quasi_topological_sort_nodes(graph, heads)
238
+ return self._sort_nodes(heads)
240
239
 
241
240
  def _find_initial_loop_nodes(self, graph: networkx.DiGraph, head):
242
241
  # TODO optimize
@@ -290,7 +289,7 @@ class RegionIdentifier(Analysis):
290
289
  # node.
291
290
  subgraph = networkx.DiGraph()
292
291
 
293
- sorted_refined_exit_nodes = GraphUtils.quasi_topological_sort_nodes(graph, refined_exit_nodes)
292
+ sorted_refined_exit_nodes = self._sort_nodes(refined_exit_nodes)
294
293
  while len(sorted_refined_exit_nodes) > 1 and new_exit_nodes:
295
294
  # visit each node in refined_exit_nodes once and determine which nodes to consider as loop nodes
296
295
  candidate_nodes = {}
@@ -324,7 +323,7 @@ class RegionIdentifier(Analysis):
324
323
 
325
324
  sorted_refined_exit_nodes += list(new_exit_nodes)
326
325
  sorted_refined_exit_nodes = list(set(sorted_refined_exit_nodes))
327
- sorted_refined_exit_nodes = GraphUtils.quasi_topological_sort_nodes(graph, sorted_refined_exit_nodes)
326
+ sorted_refined_exit_nodes = self._sort_nodes(sorted_refined_exit_nodes)
328
327
 
329
328
  refined_exit_nodes = set(sorted_refined_exit_nodes)
330
329
  refined_loop_nodes = refined_loop_nodes - refined_exit_nodes
@@ -373,37 +372,6 @@ class RegionIdentifier(Analysis):
373
372
 
374
373
  return refined_loop_nodes, refined_exit_nodes
375
374
 
376
- def _remove_self_loop(self, graph: networkx.DiGraph):
377
- r = False
378
-
379
- while True:
380
- for node in graph.nodes():
381
- if node in graph[node]:
382
- # found a self loop
383
- self._remove_node(graph, node)
384
- r = True
385
- break
386
- else:
387
- break
388
-
389
- return r
390
-
391
- def _merge_single_entry_node(self, graph: networkx.DiGraph):
392
- r = False
393
-
394
- while True:
395
- for node in networkx.dfs_postorder_nodes(graph):
396
- preds = list(graph.predecessors(node))
397
- if len(preds) == 1:
398
- # merge the two nodes
399
- self._absorb_node(graph, preds[0], node)
400
- r = True
401
- break
402
- else:
403
- break
404
-
405
- return r
406
-
407
375
  def _make_regions(self, graph: networkx.DiGraph):
408
376
  structured_loop_headers = set()
409
377
  new_regions = []
@@ -535,7 +503,14 @@ class RegionIdentifier(Analysis):
535
503
  abnormal_exit_nodes = set()
536
504
 
537
505
  region = self._abstract_cyclic_region(
538
- graph, refined_loop_nodes, head, normal_entries, abnormal_entries, normal_exit_node, abnormal_exit_nodes
506
+ graph,
507
+ refined_loop_nodes,
508
+ head,
509
+ normal_entries,
510
+ abnormal_entries,
511
+ normal_exit_node,
512
+ abnormal_exit_nodes,
513
+ self._node_order,
539
514
  )
540
515
  if region.successors is not None and len(region.successors) > 1 and self._force_loop_single_exit:
541
516
  # multi-successor region. refinement is required
@@ -661,6 +636,10 @@ class RegionIdentifier(Analysis):
661
636
  graph.remove_edge(region, succ)
662
637
  graph.add_edge(cond, succ, **edge_data)
663
638
 
639
+ # compute the node order of newly created nodes
640
+ self._node_order[region] = region_node_order = min(self._node_order[node_] for node_ in region.graph)
641
+ self._node_order[cond] = region_node_order[0], region_node_order[1] + 1
642
+
664
643
  #
665
644
  # Acyclic regions
666
645
  #
@@ -733,6 +712,7 @@ class RegionIdentifier(Analysis):
733
712
  graph,
734
713
  GraphRegion(node, subgraph, None, None, False, None, cyclic_ancestor=cyclic),
735
714
  [],
715
+ self._node_order,
736
716
  secondary_graph=secondary_graph,
737
717
  )
738
718
  continue
@@ -780,7 +760,12 @@ class RegionIdentifier(Analysis):
780
760
  l.debug("Node %r, frontier %r.", node, frontier)
781
761
  # l.debug("Identified an acyclic region %s.", self._dbg_block_list(region.graph.nodes()))
782
762
  self._abstract_acyclic_region(
783
- graph, region, frontier, dummy_endnode=dummy_endnode, secondary_graph=secondary_graph
763
+ graph,
764
+ region,
765
+ frontier,
766
+ self._node_order,
767
+ dummy_endnode=dummy_endnode,
768
+ secondary_graph=secondary_graph,
784
769
  )
785
770
  # assert dummy_endnode not in graph
786
771
  region_created = True
@@ -909,11 +894,17 @@ class RegionIdentifier(Analysis):
909
894
  )
910
895
  return None
911
896
 
897
+ @staticmethod
912
898
  def _abstract_acyclic_region(
913
- self, graph: networkx.DiGraph, region, frontier, dummy_endnode=None, secondary_graph=None
899
+ graph: networkx.DiGraph,
900
+ region,
901
+ frontier,
902
+ node_order: dict[Any, tuple[int, int]],
903
+ dummy_endnode=None,
904
+ secondary_graph=None,
914
905
  ):
915
- in_edges = self._region_in_edges(graph, region, data=True)
916
- out_edges = self._region_out_edges(graph, region, data=True)
906
+ in_edges = RegionIdentifier._region_in_edges(graph, region, data=True)
907
+ out_edges = RegionIdentifier._region_out_edges(graph, region, data=True)
917
908
 
918
909
  nodes_set = set()
919
910
  for node_ in list(region.graph.nodes()):
@@ -922,6 +913,7 @@ class RegionIdentifier(Analysis):
922
913
  graph.remove_node(node_)
923
914
 
924
915
  graph.add_node(region)
916
+ node_order[region] = min(node_order[node_] for node_ in nodes_set)
925
917
 
926
918
  for src, _, data in in_edges:
927
919
  if src not in nodes_set:
@@ -937,7 +929,7 @@ class RegionIdentifier(Analysis):
937
929
  graph.add_edge(region, frontier_node)
938
930
 
939
931
  if secondary_graph is not None:
940
- self._abstract_acyclic_region(secondary_graph, region, {})
932
+ RegionIdentifier._abstract_acyclic_region(secondary_graph, region, {}, node_order)
941
933
 
942
934
  @staticmethod
943
935
  def _abstract_cyclic_region(
@@ -948,6 +940,7 @@ class RegionIdentifier(Analysis):
948
940
  abnormal_entries,
949
941
  normal_exit_node,
950
942
  abnormal_exit_nodes,
943
+ node_order: dict[Any, tuple[int, int]],
951
944
  ):
952
945
  region = GraphRegion(head, None, None, None, True, None)
953
946
 
@@ -1019,6 +1012,8 @@ class RegionIdentifier(Analysis):
1019
1012
  graph.add_node(region)
1020
1013
  for src, dst, data in delayed_edges:
1021
1014
  graph.add_edge(src, dst, **data)
1015
+ # update node order
1016
+ node_order[region] = node_order[head]
1022
1017
 
1023
1018
  region.full_graph = full_graph
1024
1019
 
@@ -1039,25 +1034,8 @@ class RegionIdentifier(Analysis):
1039
1034
  out_edges.append((region, dst, data_))
1040
1035
  return out_edges
1041
1036
 
1042
- def _remove_node(self, graph: networkx.DiGraph, node): # pylint:disable=no-self-use
1043
- in_edges = [(src, dst, data) for (src, dst, data) in graph.in_edges(node, data=True) if src is not node]
1044
- out_edges = [(src, dst, data) for (src, dst, data) in graph.out_edges(node, data=True) if dst is not node]
1045
-
1046
- # true case: it forms a region by itself :-)
1047
- new_node = None if len(in_edges) <= 1 and len(out_edges) <= 1 else MultiNode([node])
1048
-
1049
- graph.remove_node(node)
1050
-
1051
- if new_node is not None:
1052
- for src, _, data in in_edges:
1053
- graph.add_edge(src, new_node, **data)
1054
-
1055
- for _, dst, data in out_edges:
1056
- graph.add_edge(new_node, dst, **data)
1057
-
1058
- def _merge_nodes(
1059
- self, graph: networkx.DiGraph, node_a, node_b, force_multinode=False
1060
- ): # pylint:disable=no-self-use
1037
+ @staticmethod
1038
+ def _merge_nodes(graph: networkx.DiGraph, node_a, node_b, force_multinode=False):
1061
1039
  in_edges = list(graph.in_edges(node_a, data=True))
1062
1040
  out_edges = list(graph.out_edges(node_b, data=True))
1063
1041
 
@@ -1089,9 +1067,116 @@ class RegionIdentifier(Analysis):
1089
1067
 
1090
1068
  return new_node
1091
1069
 
1092
- def _absorb_node(
1093
- self, graph: networkx.DiGraph, node_mommy, node_kiddie, force_multinode=False
1094
- ): # pylint:disable=no-self-use
1070
+ def _ensure_jump_at_loop_exit_ends(self, node: Block | MultiNode) -> None:
1071
+ if isinstance(node, Block):
1072
+ if not node.statements:
1073
+ node.statements.append(
1074
+ Jump(
1075
+ None,
1076
+ Const(None, None, node.addr + node.original_size, self.project.arch.bits),
1077
+ ins_addr=node.addr,
1078
+ )
1079
+ )
1080
+ else:
1081
+ if not isinstance(first_nonlabel_nonphi_statement(node), ConditionalJump) and not isinstance(
1082
+ node.statements[-1],
1083
+ (
1084
+ Jump,
1085
+ ConditionalJump,
1086
+ IncompleteSwitchCaseHeadStatement,
1087
+ ),
1088
+ ):
1089
+ node.statements.append(
1090
+ Jump(
1091
+ None,
1092
+ Const(None, None, node.addr + node.original_size, self.project.arch.bits),
1093
+ ins_addr=node.addr,
1094
+ )
1095
+ )
1096
+ elif isinstance(node, MultiNode) and node.nodes:
1097
+ self._ensure_jump_at_loop_exit_ends(node.nodes[-1])
1098
+
1099
+ @staticmethod
1100
+ def _dbg_block_list(blocks):
1101
+ return [(hex(b.addr) if hasattr(b, "addr") else repr(b)) for b in blocks]
1102
+
1103
+ #
1104
+ # Reducibility
1105
+ #
1106
+
1107
+ def test_reducibility(self) -> bool:
1108
+ # make a copy of the graph
1109
+ graph = networkx.DiGraph(self._graph)
1110
+
1111
+ # preprocess: make it a super graph
1112
+ self._make_supergraph(graph)
1113
+
1114
+ while True:
1115
+ changed = False
1116
+
1117
+ # find a node with a back-edge, remove the edge (deleting the loop), and replace it with a MultiNode
1118
+ changed |= self._remove_self_loop(graph)
1119
+
1120
+ # find a node that has only one predecessor, and merge it with its predecessor (replace them with a
1121
+ # MultiNode)
1122
+ changed |= self._merge_single_entry_node(graph)
1123
+
1124
+ if not changed:
1125
+ # a fixed-point is reached
1126
+ break
1127
+
1128
+ # Flow graph reducibility, Hecht and Ullman
1129
+ return len(graph.nodes) == 1
1130
+
1131
+ def _remove_self_loop(self, graph: networkx.DiGraph) -> bool:
1132
+ r = False
1133
+
1134
+ while True:
1135
+ for node in graph.nodes():
1136
+ if node in graph[node]:
1137
+ # found a self loop
1138
+ self._remove_node(graph, node)
1139
+ r = True
1140
+ break
1141
+ else:
1142
+ break
1143
+
1144
+ return r
1145
+
1146
+ def _merge_single_entry_node(self, graph: networkx.DiGraph) -> bool:
1147
+ r = False
1148
+
1149
+ while True:
1150
+ for node in networkx.dfs_postorder_nodes(graph):
1151
+ preds = list(graph.predecessors(node))
1152
+ if len(preds) == 1:
1153
+ # merge the two nodes
1154
+ self._absorb_node(graph, preds[0], node)
1155
+ r = True
1156
+ break
1157
+ else:
1158
+ break
1159
+
1160
+ return r
1161
+
1162
+ def _remove_node(self, graph: networkx.DiGraph, node): # pylint:disable=no-self-use
1163
+ in_edges = [(src, dst, data) for (src, dst, data) in graph.in_edges(node, data=True) if src is not node]
1164
+ out_edges = [(src, dst, data) for (src, dst, data) in graph.out_edges(node, data=True) if dst is not node]
1165
+
1166
+ # true case: it forms a region by itself :-)
1167
+ new_node = None if len(in_edges) <= 1 and len(out_edges) <= 1 else MultiNode([node])
1168
+
1169
+ graph.remove_node(node)
1170
+
1171
+ if new_node is not None:
1172
+ for src, _, data in in_edges:
1173
+ graph.add_edge(src, new_node, **data)
1174
+
1175
+ for _, dst, data in out_edges:
1176
+ graph.add_edge(new_node, dst, **data)
1177
+
1178
+ @staticmethod
1179
+ def _absorb_node(graph: networkx.DiGraph, node_mommy, node_kiddie, force_multinode=False):
1095
1180
  in_edges_mommy = graph.in_edges(node_mommy, data=True)
1096
1181
  out_edges_mommy = graph.out_edges(node_mommy, data=True)
1097
1182
  out_edges_kiddie = graph.out_edges(node_kiddie, data=True)
@@ -1129,38 +1214,5 @@ class RegionIdentifier(Analysis):
1129
1214
  assert node_mommy not in graph
1130
1215
  assert node_kiddie not in graph
1131
1216
 
1132
- def _ensure_jump_at_loop_exit_ends(self, node: Block | MultiNode) -> None:
1133
- if isinstance(node, Block):
1134
- if not node.statements:
1135
- node.statements.append(
1136
- Jump(
1137
- None,
1138
- Const(None, None, node.addr + node.original_size, self.project.arch.bits),
1139
- ins_addr=node.addr,
1140
- )
1141
- )
1142
- else:
1143
- if not isinstance(first_nonlabel_nonphi_statement(node), ConditionalJump) and not isinstance(
1144
- node.statements[-1],
1145
- (
1146
- Jump,
1147
- ConditionalJump,
1148
- IncompleteSwitchCaseHeadStatement,
1149
- ),
1150
- ):
1151
- node.statements.append(
1152
- Jump(
1153
- None,
1154
- Const(None, None, node.addr + node.original_size, self.project.arch.bits),
1155
- ins_addr=node.addr,
1156
- )
1157
- )
1158
- elif isinstance(node, MultiNode) and node.nodes:
1159
- self._ensure_jump_at_loop_exit_ends(node.nodes[-1])
1160
-
1161
- @staticmethod
1162
- def _dbg_block_list(blocks):
1163
- return [(hex(b.addr) if hasattr(b, "addr") else repr(b)) for b in blocks]
1164
-
1165
1217
 
1166
1218
  register_analysis(RegionIdentifier, "RegionIdentifier")
angr/analyses/smc.py CHANGED
@@ -42,6 +42,8 @@ class TraceClassifier:
42
42
  """
43
43
  addr = state.solver.eval(state.inspect.mem_write_address)
44
44
  length = state.inspect.mem_write_length
45
+ if length is None:
46
+ length = len(state.inspect.mem_write_expr) // state.arch.byte_width
45
47
  if not isinstance(length, int):
46
48
  length = state.solver.eval(length)
47
49
  self.map.add(addr, length, TraceActions.WRITE)
@@ -103,7 +105,7 @@ class SelfModifyingCodeAnalysis(Analysis):
103
105
  """
104
106
  :param subject: Subject of analysis
105
107
  :param max_bytes: Maximum number of bytes from subject address. 0 for no limit (default).
106
- :param state: State to begin executing from from.
108
+ :param state: State to begin executing from.
107
109
  """
108
110
  assert self.project.selfmodifying_code
109
111
 
@@ -2,6 +2,7 @@
2
2
  from __future__ import annotations
3
3
  import enum
4
4
  from collections import defaultdict
5
+ from contextlib import suppress
5
6
  import logging
6
7
 
7
8
  import networkx
@@ -51,23 +52,6 @@ from .dfa import DFAConstraintSolver, EmptyEpsilonNFAError
51
52
  _l = logging.getLogger(__name__)
52
53
 
53
54
 
54
- PRIMITIVE_TYPES = {
55
- TopType(),
56
- Int(),
57
- Int8(),
58
- Int16(),
59
- Int32(),
60
- Int64(),
61
- Pointer32(),
62
- Pointer64(),
63
- BottomType(),
64
- Struct(),
65
- Array(),
66
- Float(),
67
- Float32(),
68
- Float64(),
69
- }
70
-
71
55
  Top_ = TopType()
72
56
  Int_ = Int()
73
57
  Int64_ = Int64()
@@ -83,6 +67,25 @@ Float_ = Float()
83
67
  Float32_ = Float32()
84
68
  Float64_ = Float64()
85
69
 
70
+
71
+ PRIMITIVE_TYPES = {
72
+ Top_,
73
+ Int_,
74
+ Int8_,
75
+ Int16_,
76
+ Int32_,
77
+ Int64_,
78
+ Pointer32_,
79
+ Pointer64_,
80
+ Bottom_,
81
+ Struct_,
82
+ Array_,
83
+ Float_,
84
+ Float32_,
85
+ Float64_,
86
+ }
87
+
88
+
86
89
  # lattice for 64-bit binaries
87
90
  BASE_LATTICE_64 = networkx.DiGraph()
88
91
  BASE_LATTICE_64.add_edge(Top_, Int_)
@@ -149,6 +152,24 @@ class SketchNode(SketchNodeBase):
149
152
  def __hash__(self):
150
153
  return hash((SketchNode, self.typevar))
151
154
 
155
+ @property
156
+ def size(self) -> int | None:
157
+ """
158
+ Best-effort estimation of the size of the typevar (in bits). Returns None if we cannot determine.
159
+ """
160
+
161
+ if isinstance(self.typevar, DerivedTypeVariable):
162
+ last_label = self.typevar.labels[-1]
163
+ if isinstance(last_label, HasField) and last_label.bits != MAX_POINTSTO_BITS:
164
+ return last_label.bits
165
+ if isinstance(self.lower_bound, TypeConstant) and not isinstance(self.lower_bound, (TopType, BottomType)):
166
+ with suppress(NotImplementedError):
167
+ return self.lower_bound.size * 8
168
+ if isinstance(self.upper_bound, TypeConstant) and not isinstance(self.upper_bound, (TopType, BottomType)):
169
+ with suppress(NotImplementedError):
170
+ return self.upper_bound.size * 8
171
+ return None
172
+
152
173
 
153
174
  class RecursiveRefNode(SketchNodeBase):
154
175
  """
@@ -433,9 +454,8 @@ class SimpleSolver:
433
454
  if isinstance(tv, TypeVariable) and isinstance(sol, TypeConstant):
434
455
  self.solution[tv] = sol
435
456
 
436
- equ_classes, sketches, _ = self.solve()
437
457
  self._solution_cache = {}
438
- self.determine(equ_classes, sketches, self.solution)
458
+ self.solve()
439
459
  for typevar in list(self._constraints):
440
460
  self._convert_arrays(self._constraints[typevar])
441
461
 
@@ -448,6 +468,11 @@ class SimpleSolver:
448
468
  - Build the constraint graph
449
469
  - Collect all constraints
450
470
  - Apply constraints to derive the lower and upper bounds
471
+ - Determine a solution for type variables with constraints
472
+ - Rewrite the constraint graph by replacing determined type variables with their solutions
473
+ - Solve repeatedly until all interesting type variables have solutions
474
+
475
+ By repeatedly solving until exhausting interesting type variables, we ensure the S-Trans rule is applied.
451
476
  """
452
477
 
453
478
  prem_typevars = set(self._constraints) | self._typevars
@@ -476,11 +501,7 @@ class SimpleSolver:
476
501
  elif isinstance(t, TypeVariable) and t in typevars:
477
502
  constrained_typevars.add(t)
478
503
 
479
- equivalence_classes, sketches = self.infer_shapes(typevars, constraints)
480
- # TODO: Handle global variables
481
-
482
- type_schemes = constraints
483
-
504
+ _, sketches = self.infer_shapes(typevars, constraints)
484
505
  constraintset2tvs = defaultdict(set)
485
506
  for idx, tv in enumerate(constrained_typevars):
486
507
  _l.debug("Collecting constraints for type variable %r (%d/%d)", tv, idx + 1, len(constrained_typevars))
@@ -490,20 +511,43 @@ class SimpleSolver:
490
511
 
491
512
  for idx, (constraint_subset, tvs) in enumerate(constraintset2tvs.items()):
492
513
  _l.debug(
493
- "Solving %d constraints for type variables %r (%d/%d)",
514
+ "Solving %d constraints for %d type variables %r (%d/%d)",
494
515
  len(constraint_subset),
516
+ len(tvs),
495
517
  tvs,
496
518
  idx + 1,
497
519
  len(constraintset2tvs),
498
520
  )
499
- base_constraint_graph = self._generate_constraint_graph(constraint_subset, tvs | PRIMITIVE_TYPES)
500
- for idx_0, tv in enumerate(tvs):
501
- _l.debug("Solving for type variable %r (%d/%d)", tv, idx_0 + 1, len(tvs))
502
- primitive_constraints = self._generate_primitive_constraints({tv}, base_constraint_graph)
521
+
522
+ while True:
523
+ base_constraint_graph = self._generate_constraint_graph(constraint_subset, tvs | PRIMITIVE_TYPES)
524
+ primitive_constraints = self._generate_primitive_constraints(tvs, base_constraint_graph)
525
+ tvs_with_primitive_constraints = set()
503
526
  for primitive_constraint in primitive_constraints:
527
+ tv = self._typevar_from_primitive_constraint(primitive_constraint)
528
+ tvs_with_primitive_constraints.add(tv)
529
+ assert tv is not None, f"Cannot find type variable in primitive constraint {primitive_constraint}"
504
530
  sketches[tv].add_constraint(primitive_constraint)
505
-
506
- return equivalence_classes, sketches, type_schemes
531
+ solutions = {}
532
+ self.determine(sketches, tvs_with_primitive_constraints, solutions)
533
+ _l.debug("Determined solutions for %d type variable(s).", len(tvs_with_primitive_constraints))
534
+ if not solutions:
535
+ break
536
+
537
+ self.solution |= solutions
538
+
539
+ tvs = {tv for tv in tvs if tv not in tvs_with_primitive_constraints}
540
+ if not tvs:
541
+ break
542
+ # rewrite existing constraints
543
+ new_constraint_subset = set()
544
+ for constraint in constraint_subset:
545
+ rewritten = self._rewrite_constraint(constraint, solutions)
546
+ new_constraint_subset.add(rewritten)
547
+ constraint_subset = new_constraint_subset
548
+
549
+ # set the solution for missing type vars to TOP
550
+ self.determine(sketches, set(sketches).difference(set(self.solution)), self.solution)
507
551
 
508
552
  def infer_shapes(
509
553
  self, typevars: set[TypeVariable], constraints: set[TypeConstraint]
@@ -593,7 +637,6 @@ class SimpleSolver:
593
637
  non_primitive_endpoints: set[TypeVariable | DerivedTypeVariable],
594
638
  constraint_graph,
595
639
  ) -> set[TypeConstraint]:
596
- # FIXME: Extract interesting variables
597
640
  constraints_0 = self._solve_constraints_between(constraint_graph, non_primitive_endpoints, PRIMITIVE_TYPES)
598
641
  constraints_1 = self._solve_constraints_between(constraint_graph, PRIMITIVE_TYPES, non_primitive_endpoints)
599
642
  return constraints_0 | constraints_1
@@ -612,6 +655,25 @@ class SimpleSolver:
612
655
  # TODO: Other types of constraints?
613
656
  return typevars
614
657
 
658
+ @staticmethod
659
+ def _typevar_from_primitive_constraint(constraint: TypeConstraint) -> TypeVariable | None:
660
+ if isinstance(constraint, Subtype):
661
+ if (
662
+ isinstance(constraint.sub_type, DerivedTypeVariable)
663
+ and type(constraint.sub_type.type_var) is TypeVariable
664
+ ):
665
+ return constraint.sub_type.type_var
666
+ if type(constraint.sub_type) is TypeVariable:
667
+ return constraint.sub_type
668
+ if (
669
+ isinstance(constraint.super_type, DerivedTypeVariable)
670
+ and type(constraint.super_type.type_var) is TypeVariable
671
+ ):
672
+ return constraint.super_type.type_var
673
+ if type(constraint.super_type) is TypeVariable:
674
+ return constraint.super_type
675
+ return None
676
+
615
677
  @staticmethod
616
678
  def _get_all_paths(
617
679
  graph: networkx.DiGraph,
@@ -825,7 +887,6 @@ class SimpleSolver:
825
887
  """
826
888
 
827
889
  graph = networkx.DiGraph()
828
- constraints = self._get_transitive_subtype_constraints(constraints)
829
890
  for constraint in constraints:
830
891
  if isinstance(constraint, Subtype):
831
892
  self._constraint_graph_add_edges(
@@ -836,33 +897,6 @@ class SimpleSolver:
836
897
  self._constraint_graph_recall_forget_split(graph)
837
898
  return graph
838
899
 
839
- @staticmethod
840
- def _get_transitive_subtype_constraints(constraints: set[TypeConstraint]) -> set[TypeConstraint]:
841
- """
842
- Apply the S-Trans rule: a <: b, b <: c => a <: c
843
- """
844
- tv2supertypes = defaultdict(set)
845
- for constraint in constraints:
846
- if isinstance(constraint, Subtype):
847
- tv2supertypes[constraint.sub_type].add(constraint.super_type)
848
-
849
- new_constraints = set()
850
- while True:
851
- changed = False
852
- for subtype, supertypes in tv2supertypes.items():
853
- supertypes_copy = set(supertypes)
854
- for supertype in supertypes_copy:
855
- if supertype in tv2supertypes:
856
- for supertype_ in tv2supertypes[supertype]:
857
- if supertype_ not in supertypes_copy:
858
- changed = True
859
- supertypes.add(supertype_)
860
- new_constraints.add(Subtype(subtype, supertype_))
861
- if not changed:
862
- break
863
-
864
- return constraints | new_constraints
865
-
866
900
  @staticmethod
867
901
  def _constraint_graph_add_recall_edges(graph: networkx.DiGraph, node: ConstraintGraphNode) -> None:
868
902
  while True:
@@ -1004,12 +1038,7 @@ class SimpleSolver:
1004
1038
  if typevar in typevar_set:
1005
1039
  return True
1006
1040
  if isinstance(typevar, Struct) and Struct_ in typevar_set:
1007
- if not typevar.fields:
1008
- return True
1009
- return all(
1010
- SimpleSolver._typevar_inside_set(field_typevar, typevar_set)
1011
- for field_typevar in typevar.fields.values()
1012
- )
1041
+ return True
1013
1042
  if isinstance(typevar, Array) and Array_ in typevar_set:
1014
1043
  return SimpleSolver._typevar_inside_set(typevar.element, typevar_set)
1015
1044
  if isinstance(typevar, Pointer) and (Pointer32_ in typevar_set or Pointer64_ in typevar_set):
@@ -1110,31 +1139,47 @@ class SimpleSolver:
1110
1139
  return Pointer64()
1111
1140
  return t
1112
1141
 
1142
+ @staticmethod
1143
+ def _rewrite_constraint(constraint: TypeConstraint, solutions: dict) -> TypeConstraint:
1144
+ if isinstance(constraint, Subtype):
1145
+ replaced = False
1146
+ if isinstance(constraint.sub_type, TypeVariable) and constraint.sub_type in solutions:
1147
+ sub_type = solutions[constraint.sub_type]
1148
+ replaced = True
1149
+ else:
1150
+ sub_type = constraint.sub_type
1151
+ if isinstance(constraint.super_type, TypeVariable) and constraint.super_type in solutions:
1152
+ super_type = solutions[constraint.super_type]
1153
+ replaced = True
1154
+ else:
1155
+ super_type = constraint.super_type
1156
+ return Subtype(sub_type, super_type) if replaced else constraint
1157
+ return constraint
1158
+
1113
1159
  def determine(
1114
1160
  self,
1115
- equivalent_classes: dict[TypeVariable, TypeVariable],
1116
1161
  sketches,
1162
+ tvs,
1117
1163
  solution: dict,
1118
1164
  nodes: set[SketchNode] | None = None,
1119
1165
  ) -> None:
1120
1166
  """
1121
1167
  Determine C-like types from sketches.
1122
1168
 
1123
- :param equivalent_classes: A dictionary mapping each type variable from its representative in the equivalence
1124
- class over ~.
1125
1169
  :param sketches: A dictionary storing sketches for each type variable.
1126
1170
  :param solution: The dictionary storing C-like types for each type variable. Output.
1127
1171
  :param nodes: Optional. Nodes that should be considered in the sketch.
1128
1172
  :return: None
1129
1173
  """
1130
- for typevar, sketch in sketches.items():
1131
- self._determine(equivalent_classes, typevar, sketch, solution, nodes=nodes)
1132
1174
 
1133
- for v, e in self._equivalence.items():
1134
- if v not in solution and e in solution:
1135
- solution[v] = solution[e]
1175
+ for typevar in tvs:
1176
+ self._determine(typevar, sketches[typevar], solution, nodes=nodes)
1177
+
1178
+ for v, eq in self._equivalence.items():
1179
+ if v not in solution and eq in solution:
1180
+ solution[v] = solution[eq]
1136
1181
 
1137
- def _determine(self, equivalent_classes, the_typevar, sketch, solution: dict, nodes: set[SketchNode] | None = None):
1182
+ def _determine(self, the_typevar, sketch, solution: dict, nodes: set[SketchNode] | None = None):
1138
1183
  """
1139
1184
  Return the solution from sketches
1140
1185
  """
@@ -1194,7 +1239,7 @@ class SimpleSolver:
1194
1239
  for vals, out in [(func_inputs, input_args), (func_outputs, output_values)]:
1195
1240
  for idx in range(max(vals) + 1):
1196
1241
  if idx in vals:
1197
- sol = self._determine(equivalent_classes, the_typevar, sketch, solution, nodes=vals[idx])
1242
+ sol = self._determine(the_typevar, sketch, solution, nodes=vals[idx])
1198
1243
  out.append(sol)
1199
1244
  else:
1200
1245
  out.append(None)
@@ -1290,7 +1335,7 @@ class SimpleSolver:
1290
1335
  offset = sorted_offsets[i]
1291
1336
 
1292
1337
  child_nodes = node_by_offset[offset]
1293
- sol = self._determine(equivalent_classes, the_typevar, sketch, solution, nodes=child_nodes)
1338
+ sol = self._determine(the_typevar, sketch, solution, nodes=child_nodes)
1294
1339
  if isinstance(sol, TopType):
1295
1340
  # make it an array if possible
1296
1341
  elem_size = min(offset_to_sizes[offset])
@@ -1323,12 +1368,20 @@ class SimpleSolver:
1323
1368
  lower_bound = Bottom_
1324
1369
  upper_bound = Top_
1325
1370
 
1371
+ node_sizes = set()
1326
1372
  for node in nodes:
1327
- lower_bound = self.join(lower_bound, node.lower_bound)
1328
- upper_bound = self.meet(upper_bound, node.upper_bound)
1329
- # TODO: Support variables that are accessed via differently sized pointers
1373
+ node_size = node.size
1374
+ if node_size is not None:
1375
+ node_sizes.add(node_size)
1376
+ if len(node_sizes) > 1:
1377
+ # multi-sized reads - cannot converge to a reasonable type
1378
+ result = Bottom_
1379
+ else:
1380
+ for node in nodes:
1381
+ lower_bound = self.join(lower_bound, node.lower_bound)
1382
+ upper_bound = self.meet(upper_bound, node.upper_bound)
1383
+ result = lower_bound if not isinstance(lower_bound, BottomType) else upper_bound
1330
1384
 
1331
- result = lower_bound if not isinstance(lower_bound, BottomType) else upper_bound
1332
1385
  for node in nodes:
1333
1386
  solution[node.typevar] = result
1334
1387
  self._solution_cache[node.typevar] = result
@@ -1386,3 +1439,12 @@ class SimpleSolver:
1386
1439
  if self.bits == 64:
1387
1440
  return Pointer64
1388
1441
  raise NotImplementedError(f"Unsupported bits {self.bits}")
1442
+
1443
+ @staticmethod
1444
+ def dump_constraint_graph(graph: networkx.DiGraph, filename: str) -> None:
1445
+ """
1446
+ Dump the constraint graph to a file.
1447
+ """
1448
+ from networkx.drawing.nx_agraph import write_dot # pylint:disable=import-outside-toplevel
1449
+
1450
+ write_dot(graph, filename)
@@ -100,7 +100,8 @@ class Typehoon(Analysis):
100
100
  and not isinstance(type_.pts_to, SimTypeArray)
101
101
  ):
102
102
  type_ = type_.pts_to
103
- type_candidates.append(type_)
103
+ if type_ is not None:
104
+ type_candidates.append(type_)
104
105
 
105
106
  # determine the best type - this logic can be made better!
106
107
  if not type_candidates:
@@ -127,7 +127,7 @@ class Function(Serializable):
127
127
  self._retout_sites: set[BlockNode] = set()
128
128
  # block nodes (basic block nodes) at whose ends the function terminates
129
129
  # in theory, if everything works fine, endpoints == ret_sites | jumpout_sites | callout_sites
130
- self._endpoints = defaultdict(set)
130
+ self._endpoints: defaultdict[str, set[BlockNode]] = defaultdict(set)
131
131
 
132
132
  self._call_sites = {}
133
133
  self.addr = addr
@@ -1358,7 +1358,7 @@ class Function(Serializable):
1358
1358
  return
1359
1359
 
1360
1360
  graph = self.transition_graph
1361
- end_addresses = defaultdict(list)
1361
+ end_addresses: defaultdict[int, list[BlockNode]] = defaultdict(list)
1362
1362
 
1363
1363
  for block in self.nodes:
1364
1364
  if isinstance(block, BlockNode):
@@ -1456,7 +1456,13 @@ class Function(Serializable):
1456
1456
  )
1457
1457
  else:
1458
1458
  # We gotta create a new one
1459
- l.error("normalize(): Please report it to Fish/maybe john.")
1459
+ l.error("normalize(): Please report it to Fish.")
1460
+
1461
+ # update endpoints
1462
+ for sortset in self._endpoints.values():
1463
+ if n in sortset:
1464
+ sortset.remove(n)
1465
+ sortset.add(smallest_node)
1460
1466
 
1461
1467
  end_addresses[end_addr] = [smallest_node]
1462
1468
 
@@ -1680,7 +1686,7 @@ class Function(Serializable):
1680
1686
  n = separator
1681
1687
  if must_disambiguate_by_addr:
1682
1688
  n += hex(self.addr) + separator
1683
- elif self.binary is not self.project.loader.main_object:
1689
+ elif self.binary is not self.project.loader.main_object and self.binary_name is not None:
1684
1690
  n += self.binary_name + separator
1685
1691
  return n + (display_name or self.name)
1686
1692
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: angr
3
- Version: 9.2.152
3
+ Version: 9.2.153
4
4
  Summary: A multi-architecture binary analysis toolkit, with the ability to perform dynamic symbolic execution and various static analyses on binaries
5
5
  License: BSD-2-Clause
6
6
  Project-URL: Homepage, https://angr.io/
@@ -17,13 +17,13 @@ Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Requires-Dist: cxxheaderparser
19
19
  Requires-Dist: GitPython
20
- Requires-Dist: ailment==9.2.152
21
- Requires-Dist: archinfo==9.2.152
20
+ Requires-Dist: ailment==9.2.153
21
+ Requires-Dist: archinfo==9.2.153
22
22
  Requires-Dist: cachetools
23
23
  Requires-Dist: capstone==5.0.3
24
24
  Requires-Dist: cffi>=1.14.0
25
- Requires-Dist: claripy==9.2.152
26
- Requires-Dist: cle==9.2.152
25
+ Requires-Dist: claripy==9.2.153
26
+ Requires-Dist: cle==9.2.153
27
27
  Requires-Dist: mulpyplexer
28
28
  Requires-Dist: networkx!=2.8.1,>=2.0
29
29
  Requires-Dist: protobuf>=5.28.2
@@ -31,7 +31,7 @@ Requires-Dist: psutil
31
31
  Requires-Dist: pycparser>=2.18
32
32
  Requires-Dist: pydemumble
33
33
  Requires-Dist: pyformlang
34
- Requires-Dist: pyvex==9.2.152
34
+ Requires-Dist: pyvex==9.2.153
35
35
  Requires-Dist: rich>=13.1.0
36
36
  Requires-Dist: sortedcontainers
37
37
  Requires-Dist: sympy
@@ -1,4 +1,4 @@
1
- angr/__init__.py,sha256=I7kOb1_OagvgZ0ckx5c3aCv2LU7e2Xm4vSrXEYT4tQE,9153
1
+ angr/__init__.py,sha256=ApROccv7-zzv89AOX-4Ox3WeQbu3W39xfautbq4aWfk,9153
2
2
  angr/__main__.py,sha256=AK9V6uPZ58UuTKmmiH_Kgn5pG9AvjnmJCPOku69A-WU,4993
3
3
  angr/annocfg.py,sha256=0NIvcuCskwz45hbBzigUTAuCrYutjDMwEXtMJf0y0S0,10742
4
4
  angr/blade.py,sha256=NhesOPloKJC1DQJRv_HBT18X7oNxK16JwAfNz2Lc1o0,15384
@@ -54,7 +54,7 @@ angr/analyses/proximity_graph.py,sha256=-g7pNpbP2HQhKW3w1Eff23K8vAsgWWYoe3wVxRh3
54
54
  angr/analyses/reassembler.py,sha256=UXrDQNJtn4RUurpbIyMVpQ3AZ0VGVQZatoGHziEHvU0,98357
55
55
  angr/analyses/s_liveness.py,sha256=K4soSrcQE9pIn7Yf2Lb3LZEu1ymuQVpWzOqLKunFDGQ,7974
56
56
  angr/analyses/s_propagator.py,sha256=4MUmjo1aozCT-UeN9IMYlxtMjCoTM6hWwYaYTTjwvCQ,24904
57
- angr/analyses/smc.py,sha256=0fvLPUpjlg6GCjYnfSqanXkGYlthmPwqMYR-ZYBHsbo,5075
57
+ angr/analyses/smc.py,sha256=UyVaTBms0KI9jRUBhbnz1s6ez_K_oRy4qoPsvxwnoQY,5177
58
58
  angr/analyses/soot_class_hierarchy.py,sha256=R4xeacn-a_Q7PxSyj_stu5mnglZkPB5US5srKChX3mk,8740
59
59
  angr/analyses/stack_pointer_tracker.py,sha256=XcqCwqurI8x-N4mU_yfQWwIQNkj3fTtXYkUvw2PFIzw,37821
60
60
  angr/analyses/static_hooker.py,sha256=AYJXoHtdq2m-MgpJbx4eur7wy7llrKXvsVM5NdPcKHU,1852
@@ -71,9 +71,9 @@ angr/analyses/cfg/__init__.py,sha256=-w8Vd6FD6rtjlQaQ7MxwmliFgS2zt-kZepAY4gHas04
71
71
  angr/analyses/cfg/cfb.py,sha256=scykl1FJvqcTe2x69zreWi0PG_zYMbka3k6tlRwaD_g,15367
72
72
  angr/analyses/cfg/cfg.py,sha256=dc9M91CaLeEKduYfMwpsT_01x6XyYuoNvgvcDKtbN-I,3177
73
73
  angr/analyses/cfg/cfg_arch_options.py,sha256=_XRewFZ51SeNaxChadb6_ER7-8LW8KXeTIpoP8_iRj0,3506
74
- angr/analyses/cfg/cfg_base.py,sha256=o4uG2ob88DdVcDvA9sdjDUo7GPKt9ERXJEgWnKiWDdA,123440
74
+ angr/analyses/cfg/cfg_base.py,sha256=VEsUvo4ySnvMvrphcJjAhCHfh7BX9jmY7KrHc2U_Hgc,123441
75
75
  angr/analyses/cfg/cfg_emulated.py,sha256=wL0ABJMZ8EwKbNjrpE_eqCkZpHDt4y6lmoQOmAIcJMQ,148235
76
- angr/analyses/cfg/cfg_fast.py,sha256=1aQtubXAXkw3tCfxRjUD2BXSlRH1obMbmaDQvs9qrzo,228422
76
+ angr/analyses/cfg/cfg_fast.py,sha256=nZVk_Wm1ylS3acBYKN_TDD-8sKg67Gg7mhOI54TYfrA,230949
77
77
  angr/analyses/cfg/cfg_fast_soot.py,sha256=8YgMtY_8w4nAMcHR6n-q_eFvKwsvNz0anUH7EzIL1B4,25924
78
78
  angr/analyses/cfg/cfg_job_base.py,sha256=Zshze972MakTsd-licQz77lac17igQaaTsAteHeHhYQ,5974
79
79
  angr/analyses/cfg/indirect_jump_resolvers/__init__.py,sha256=qWiTSIAQgXWmaYa9YYaiKsSTwUVClymaXv9sCX-bY-k,835
@@ -101,13 +101,13 @@ angr/analyses/data_dep/data_dependency_analysis.py,sha256=_vQPkw1NMrzD7kAFeotOaa
101
101
  angr/analyses/data_dep/dep_nodes.py,sha256=LcNcxeuKXMMc0GkmvKqqFwNlAk3GhzBR8ixM4CD305k,4640
102
102
  angr/analyses/data_dep/sim_act_location.py,sha256=EXmfFF3lV9XogcB2gFRMUoJCbjpDYiSKNyfafkBfiY8,1564
103
103
  angr/analyses/decompiler/__init__.py,sha256=eyxt2UKvPkbuS_l_1GPb0CJ6hrj2wTavh-mVf23wwiQ,1162
104
- angr/analyses/decompiler/ail_simplifier.py,sha256=BWMyuu_Y9ZKTtbykOo3xe7A8M3z9twXbc_2DUfNx7qo,79900
104
+ angr/analyses/decompiler/ail_simplifier.py,sha256=x6B5ex0eoZgH80yLmMZbXViZKYZI1NU77cibN30qpfs,79886
105
105
  angr/analyses/decompiler/ailgraph_walker.py,sha256=m71HCthOr9J8PZoMxJzCPskay8yfCZ2j8esWT4Ka3KI,1630
106
106
  angr/analyses/decompiler/block_io_finder.py,sha256=xMwG8Bi69OGNYVs0U0F4yxM8kEsnyrsMrf0gEr8dOEw,10923
107
107
  angr/analyses/decompiler/block_similarity.py,sha256=SseCdWgh-kS9q_C_BRxlQ4OwCRQfg-9IyncxKXm_OG8,6849
108
108
  angr/analyses/decompiler/block_simplifier.py,sha256=Di5UXgBIXp0pa3_ubHY4k9vj927xAFR3oCUZ16Q3WvE,14229
109
109
  angr/analyses/decompiler/callsite_maker.py,sha256=ZjtLdxDCLS0WPqOik9bCek2LyuAtQNYA4V-yqGLeENo,23032
110
- angr/analyses/decompiler/clinic.py,sha256=GyRoxuRtsQDv6uzvTYJXZ-GYGOFa5etFTa03UzSuvTE,144399
110
+ angr/analyses/decompiler/clinic.py,sha256=5gs11WIfT7HAFKvVGdPjQHgrMRO8SXHw2zra1r9j63A,146384
111
111
  angr/analyses/decompiler/condition_processor.py,sha256=61VDwVA1e-oKsv0N8kvh3c5QOdQixrkBZcm3RLuw7KU,52679
112
112
  angr/analyses/decompiler/decompilation_cache.py,sha256=oNkeyrEXhyinrN7-fKeDEuGP6I_oAclGjRS4Aa36FoE,1488
113
113
  angr/analyses/decompiler/decompilation_options.py,sha256=NDB67DI1L-stvJ4b1eQkfV26HgDJ_rG9-6PEv08G9-8,8195
@@ -120,7 +120,7 @@ angr/analyses/decompiler/jump_target_collector.py,sha256=qR11VsIp6H1N-19xCdXMRs1
120
120
  angr/analyses/decompiler/jumptable_entry_condition_rewriter.py,sha256=f_JyNiSZfoudElfl2kIzONoYCiosR4xYFOe8Q5SkvLg,2176
121
121
  angr/analyses/decompiler/label_collector.py,sha256=JLaGuSZu-DdJMBTYOPt4QpWJ6UigOpsC5bgNANrSao4,798
122
122
  angr/analyses/decompiler/redundant_label_remover.py,sha256=J9hpP3C_P08v84FjVU0q5Rmj5M1N9q3HKWSWsA2u7Yg,5879
123
- angr/analyses/decompiler/region_identifier.py,sha256=iZ3bTHWwf3wRaxD3Z3nUZtqUkUj8at1rGSFNpDRMvWg,49473
123
+ angr/analyses/decompiler/region_identifier.py,sha256=YsJp16bHNOEvhHYu0Dw1tAorm2eM84DsxF4Ilwh5htw,51184
124
124
  angr/analyses/decompiler/region_walker.py,sha256=u0hR0bEX1hSwkv-vejIM1gS-hcX2F2DLsDqpKhQ5_pQ,752
125
125
  angr/analyses/decompiler/return_maker.py,sha256=pKn9_y5VXqTeJnD5uzLLd9sH_Dp_9wkPcWPiJPTV-7A,2550
126
126
  angr/analyses/decompiler/seq_to_blocks.py,sha256=bB-1m8oBO59AlAp6izAROks3BBxFW8zigLlrIMt6Yfs,564
@@ -363,10 +363,10 @@ angr/analyses/s_reaching_definitions/s_reaching_definitions.py,sha256=_SooCn9qpw
363
363
  angr/analyses/typehoon/__init__.py,sha256=KjKBUZadAd3grXUy48_qO0L4Me-riSqPGteVDcTL59M,92
364
364
  angr/analyses/typehoon/dfa.py,sha256=41lzhE-QmkC342SjfaaPI41lr4Au5XROTu_7oenvg7g,3823
365
365
  angr/analyses/typehoon/lifter.py,sha256=hxYJmM_A0Kl6YgY7NyWBtA3ieaY49Ey3ESCHC61lMys,4000
366
- angr/analyses/typehoon/simple_solver.py,sha256=w1qiSIFYWsQMqyayMzDRNZKH6xRnDdXyCi08dA_eCoI,54842
366
+ angr/analyses/typehoon/simple_solver.py,sha256=QMHPHz6veiu6xp9BeeTTumi5ispgjCnNo_IP8ESiFE0,57495
367
367
  angr/analyses/typehoon/translator.py,sha256=_UE1JC4KNDXXl4plula9OApK1ee07z9BFdX9HKa5uqw,10568
368
368
  angr/analyses/typehoon/typeconsts.py,sha256=jQEVziyt3LnctrSrCtbUSPi-0tjl8DKoLMFfaOEG3lI,7939
369
- angr/analyses/typehoon/typehoon.py,sha256=gi1DMDbqP8TkpxNiNoaTKPGW01Hy_2iPJS-gedeWagY,12110
369
+ angr/analyses/typehoon/typehoon.py,sha256=IXC_a2N7hsq8wwUrx_UITzmjTApMZWVGYxYBtS3PBL8,12152
370
370
  angr/analyses/typehoon/typevars.py,sha256=cvbeeEDapb0LgGgtgUVpbhAcfuaylk7vEiwCqPxvtQo,16332
371
371
  angr/analyses/typehoon/variance.py,sha256=3wYw3of8uoar-MQ7gD6arALiwlJRW990t0BUqMarXIY,193
372
372
  angr/analyses/unpacker/__init__.py,sha256=tBXwDMFKN0Hp8YP0DK-c6deo0Muc_LNopvoKKbzp3Tc,190
@@ -542,7 +542,7 @@ angr/knowledge_plugins/cfg/cfg_node.py,sha256=mAvQ8XAEURM7y0suc_S9lfxCmfXSTJHmWB
542
542
  angr/knowledge_plugins/cfg/indirect_jump.py,sha256=W3KWpH7Sx-6Z7h_BwQjCK_XfP3ce_MaeAu_Aaq3D3qg,2072
543
543
  angr/knowledge_plugins/cfg/memory_data.py,sha256=QLxFZfrtwz8u6UJn1L-Sxa-C8S0Gy9IOlfNfHCLPIow,5056
544
544
  angr/knowledge_plugins/functions/__init__.py,sha256=asiLNiT6sHbjP6eU-kDpawIoVxv4J35cwz5yQHtQ2E0,167
545
- angr/knowledge_plugins/functions/function.py,sha256=SGQ3DnGJF0ps3P4mV_ohnMjdwmVVeAwNuxyPfwLAu00,70456
545
+ angr/knowledge_plugins/functions/function.py,sha256=vzpTLise4KKkLkQwq9LRYZ4NUkioh-zZphwBIG74euY,70770
546
546
  angr/knowledge_plugins/functions/function_manager.py,sha256=YWp9Hc-Rx9iYChJ3hFv9Tjat-6ZUidv1xsSZLQ2tL9Q,20469
547
547
  angr/knowledge_plugins/functions/function_parser.py,sha256=DTdVwYt6nXLMc0EOh-V_GhvZYQ947UNBaA77qn7Y6Vo,12379
548
548
  angr/knowledge_plugins/functions/soot_function.py,sha256=OzCvQPWxnjbwPWTW0JXrQey4zyaayHD_v6ZA7nJ4YJw,4850
@@ -1384,9 +1384,9 @@ angr/utils/types.py,sha256=5EDtrusFLf1fIcMz8fgJiPPsUhpEm0bf_oqZ_PSRje0,1836
1384
1384
  angr/utils/ssa/__init__.py,sha256=ZUPoK7Y1k-7vQkvoYUYPMdjfGh4oC6W3VbWzV_udZHg,14020
1385
1385
  angr/utils/ssa/tmp_uses_collector.py,sha256=rSpvMxBHzg-tmvhsfjn3iLyPEKzaZN-xpQrdslMq3J4,793
1386
1386
  angr/utils/ssa/vvar_uses_collector.py,sha256=O2aNZeM5DL8qatyhYuMhgbYGFp6Onm2yr9pKq1wRjA0,1347
1387
- angr-9.2.152.dist-info/licenses/LICENSE,sha256=PmWf0IlSz6Jjp9n7nyyBQA79Q5C2ma68LRykY1V3GF0,1456
1388
- angr-9.2.152.dist-info/METADATA,sha256=gen2o641GCTQ_68STSXm_FqZ_lp6gRZXlxlv4wBABhY,4910
1389
- angr-9.2.152.dist-info/WHEEL,sha256=0V4x4m9tN81LAvnzQTf8-fo7rXznSFgjzUkfKMeGVAA,109
1390
- angr-9.2.152.dist-info/entry_points.txt,sha256=Vjh1C8PMyr5dZFMnik5WkEP01Uwr2T73I3a6N32sgQU,44
1391
- angr-9.2.152.dist-info/top_level.txt,sha256=dKw0KWTbwLXytFvv15oAAG4sUs3ey47tt6DorJG9-hw,5
1392
- angr-9.2.152.dist-info/RECORD,,
1387
+ angr-9.2.153.dist-info/licenses/LICENSE,sha256=PmWf0IlSz6Jjp9n7nyyBQA79Q5C2ma68LRykY1V3GF0,1456
1388
+ angr-9.2.153.dist-info/METADATA,sha256=EiC80ame406IE0Q0DeYLVD3JFIgtsPhFSjq7A5yiI1g,4910
1389
+ angr-9.2.153.dist-info/WHEEL,sha256=_KUVcXRhJEc-8UBArmg0ZPhMJMi6BfemltWFwwxKBcg,109
1390
+ angr-9.2.153.dist-info/entry_points.txt,sha256=Vjh1C8PMyr5dZFMnik5WkEP01Uwr2T73I3a6N32sgQU,44
1391
+ angr-9.2.153.dist-info/top_level.txt,sha256=dKw0KWTbwLXytFvv15oAAG4sUs3ey47tt6DorJG9-hw,5
1392
+ angr-9.2.153.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.0)
2
+ Generator: setuptools (80.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-manylinux2014_aarch64
5
5