angr 9.2.156__cp310-cp310-manylinux2014_aarch64.whl → 9.2.157__cp310-cp310-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 (34) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/cfg_base.py +87 -71
  3. angr/analyses/cfg/cfg_fast.py +5 -0
  4. angr/analyses/decompiler/clinic.py +182 -104
  5. angr/analyses/decompiler/decompiler.py +11 -0
  6. angr/analyses/decompiler/dephication/graph_vvar_mapping.py +1 -1
  7. angr/analyses/decompiler/structured_codegen/c.py +18 -5
  8. angr/analyses/disassembly.py +5 -11
  9. angr/analyses/s_propagator.py +2 -4
  10. angr/analyses/stack_pointer_tracker.py +3 -7
  11. angr/analyses/typehoon/simple_solver.py +3 -3
  12. angr/analyses/variable_recovery/engine_base.py +2 -8
  13. angr/analyses/variable_recovery/variable_recovery.py +4 -3
  14. angr/calling_conventions.py +3 -3
  15. angr/engines/hook.py +1 -1
  16. angr/engines/icicle.py +229 -0
  17. angr/engines/pcode/behavior.py +1 -4
  18. angr/engines/pcode/emulate.py +1 -4
  19. angr/engines/pcode/lifter.py +2 -10
  20. angr/engines/vex/claripy/irop.py +2 -2
  21. angr/knowledge_plugins/functions/function.py +18 -10
  22. angr/knowledge_plugins/functions/function_manager.py +68 -5
  23. angr/knowledge_plugins/variables/variable_manager.py +15 -3
  24. angr/rustylib.cpython-310-aarch64-linux-gnu.so +0 -0
  25. angr/sim_variable.py +31 -0
  26. angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
  27. angr/storage/memory_mixins/convenient_mappings_mixin.py +1 -1
  28. {angr-9.2.156.dist-info → angr-9.2.157.dist-info}/METADATA +7 -8
  29. {angr-9.2.156.dist-info → angr-9.2.157.dist-info}/RECORD +33 -33
  30. {angr-9.2.156.dist-info → angr-9.2.157.dist-info}/WHEEL +1 -1
  31. angr/rustylib.pyi +0 -165
  32. {angr-9.2.156.dist-info → angr-9.2.157.dist-info}/entry_points.txt +0 -0
  33. {angr-9.2.156.dist-info → angr-9.2.157.dist-info}/licenses/LICENSE +0 -0
  34. {angr-9.2.156.dist-info → angr-9.2.157.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.156"
5
+ __version__ = "9.2.157"
6
6
 
7
7
  if bytes is str:
8
8
  raise Exception(
@@ -1147,7 +1147,8 @@ class CFGBase(Analysis):
1147
1147
  graph = self.graph
1148
1148
 
1149
1149
  smallest_nodes = {} # indexed by end address of the node
1150
- end_addresses_to_nodes = defaultdict(set)
1150
+ end_addr_to_node = {} # a dictionary from node key to node *if* only one node exists for the key
1151
+ end_addr_to_nodes = defaultdict(list) # a dictionary from node key to nodes *if* more than one node exist
1151
1152
 
1152
1153
  for n in graph.nodes():
1153
1154
  if n.is_simprocedure:
@@ -1155,76 +1156,89 @@ class CFGBase(Analysis):
1155
1156
  end_addr = n.addr + n.size
1156
1157
  key = (end_addr, n.callstack_key)
1157
1158
  # add the new item
1158
- end_addresses_to_nodes[key].add(n)
1159
-
1160
- for key in list(end_addresses_to_nodes.keys()):
1161
- if len(end_addresses_to_nodes[key]) == 1:
1162
- smallest_nodes[key] = next(iter(end_addresses_to_nodes[key]))
1163
- del end_addresses_to_nodes[key]
1159
+ if key not in end_addr_to_node:
1160
+ # this is the first node of this key
1161
+ end_addr_to_node[key] = n
1162
+ else:
1163
+ # this is the 2nd+ node of this key
1164
+ if key not in end_addr_to_nodes:
1165
+ end_addr_to_nodes[key].append(end_addr_to_node[key])
1166
+ end_addr_to_nodes[key].append(n)
1167
+
1168
+ # update smallest_nodes
1169
+ for key, node in end_addr_to_node.items():
1170
+ if key in end_addr_to_nodes:
1171
+ continue
1172
+ smallest_nodes[key] = node
1173
+ del end_addr_to_node # micro memory optimization
1164
1174
 
1165
- while end_addresses_to_nodes:
1175
+ while end_addr_to_nodes:
1166
1176
  key_to_find = (None, None)
1167
- for tpl, x in end_addresses_to_nodes.items():
1168
- if len(x) > 1:
1169
- key_to_find = tpl
1170
- break
1177
+ for tpl in list(end_addr_to_nodes):
1178
+ x = end_addr_to_nodes[tpl]
1179
+ if len(x) <= 1:
1180
+ continue
1181
+ key_to_find = tpl
1171
1182
 
1172
- end_addr, callstack_key = key_to_find
1173
- all_nodes = end_addresses_to_nodes[key_to_find]
1183
+ end_addr, callstack_key = key_to_find
1184
+ all_nodes = end_addr_to_nodes[key_to_find]
1174
1185
 
1175
- all_nodes = sorted(all_nodes, key=lambda node: node.addr, reverse=True)
1176
- smallest_node = all_nodes[0] # take the one that has the highest address
1177
- other_nodes = all_nodes[1:]
1186
+ all_nodes = sorted(all_nodes, key=lambda node: node.addr, reverse=True)
1187
+ smallest_node = all_nodes[0] # take the one that has the highest address
1188
+ other_nodes = all_nodes[1:]
1178
1189
 
1179
- self._normalize_core(
1180
- graph, callstack_key, smallest_node, other_nodes, smallest_nodes, end_addresses_to_nodes
1181
- )
1190
+ self._normalize_core(
1191
+ graph, callstack_key, smallest_node, other_nodes, smallest_nodes, end_addr_to_nodes
1192
+ )
1182
1193
 
1183
- del end_addresses_to_nodes[key_to_find]
1184
- # make sure the smallest node is stored in end_addresses
1185
- smallest_nodes[key_to_find] = smallest_node
1186
-
1187
- # corner case
1188
- # sometimes two overlapping blocks may not be ending at the instruction. this might happen when one of the
1189
- # blocks (the bigger one) hits the instruction count limit or bytes limit before reaching the end address
1190
- # of the smaller block. in this case we manually pick up those blocks.
1191
- if not end_addresses_to_nodes:
1192
- # find if there are still overlapping blocks
1193
- sorted_smallest_nodes = defaultdict(list) # callstack_key is the key of this dict
1194
- for k, node in smallest_nodes.items():
1195
- _, callstack_key = k
1196
- sorted_smallest_nodes[callstack_key].append(node)
1197
- for k in sorted_smallest_nodes:
1198
- sorted_smallest_nodes[k] = sorted(sorted_smallest_nodes[k], key=lambda node: node.addr)
1199
-
1200
- for callstack_key, lst in sorted_smallest_nodes.items():
1201
- lst_len = len(lst)
1202
- for i, node in enumerate(lst):
1203
- if i == lst_len - 1:
1204
- break
1205
- next_node = lst[i + 1]
1206
- if node is not next_node and node.addr <= next_node.addr < node.addr + node.size:
1207
- # umm, those nodes are overlapping, but they must have different end addresses
1208
- nodekey_a = node.addr + node.size, callstack_key
1209
- nodekey_b = next_node.addr + next_node.size, callstack_key
1210
- if nodekey_a == nodekey_b:
1211
- # error handling: this will only happen if we have completely overlapping nodes
1212
- # caused by different jumps (one of the jumps is probably incorrect), which usually
1213
- # indicates an error in CFG recovery. we print a warning and skip this node
1214
- l.warning(
1215
- "Found completely overlapping nodes %s. It usually indicates an error in CFG "
1216
- "recovery. Skip.",
1217
- node,
1218
- )
1219
- continue
1220
-
1221
- if nodekey_a in smallest_nodes and nodekey_b in smallest_nodes:
1222
- # misuse end_addresses_to_nodes
1223
- end_addresses_to_nodes[(node.addr + node.size, callstack_key)].add(node)
1224
- end_addresses_to_nodes[(node.addr + node.size, callstack_key)].add(next_node)
1225
-
1226
- smallest_nodes.pop(nodekey_a, None)
1227
- smallest_nodes.pop(nodekey_b, None)
1194
+ del end_addr_to_nodes[key_to_find]
1195
+ # make sure the smallest node is stored in end_addresses
1196
+ smallest_nodes[key_to_find] = smallest_node
1197
+
1198
+ # corner case
1199
+ # sometimes two overlapping blocks may not end at the instruction. this might happen when one of the
1200
+ # blocks (the bigger one) hits the instruction count limit or bytes limit before reaching the end
1201
+ # address of the smaller block. in this case we manually pick up those blocks.
1202
+ if not end_addr_to_nodes:
1203
+ # find if there are still overlapping blocks
1204
+ sorted_smallest_nodes = defaultdict(list) # callstack_key is the key of this dict
1205
+ for k, node in smallest_nodes.items():
1206
+ _, callstack_key = k
1207
+ sorted_smallest_nodes[callstack_key].append(node)
1208
+ for k in sorted_smallest_nodes:
1209
+ sorted_smallest_nodes[k] = sorted(sorted_smallest_nodes[k], key=lambda node: node.addr)
1210
+
1211
+ for callstack_key, lst in sorted_smallest_nodes.items():
1212
+ lst_len = len(lst)
1213
+ for i, node in enumerate(lst):
1214
+ if i == lst_len - 1:
1215
+ break
1216
+ next_node = lst[i + 1]
1217
+ if node is not next_node and node.addr <= next_node.addr < node.addr + node.size:
1218
+ # umm, those nodes are overlapping, but they must have different end addresses
1219
+ nodekey_a = node.addr + node.size, callstack_key
1220
+ nodekey_b = next_node.addr + next_node.size, callstack_key
1221
+ if nodekey_a == nodekey_b:
1222
+ # error handling: this will only happen if we have completely overlapping nodes
1223
+ # caused by different jumps (one of the jumps is probably incorrect), which usually
1224
+ # indicates an error in CFG recovery. we print a warning and skip this node
1225
+ l.warning(
1226
+ "Found completely overlapping nodes %s. It usually indicates an error in CFG "
1227
+ "recovery. Skip.",
1228
+ node,
1229
+ )
1230
+ continue
1231
+
1232
+ if nodekey_a in smallest_nodes and nodekey_b in smallest_nodes:
1233
+ # misuse end_addresses_to_nodes
1234
+ key = node.addr + node.size, callstack_key
1235
+ if node not in end_addr_to_nodes[key]:
1236
+ end_addr_to_nodes[key].append(node)
1237
+ if next_node not in end_addr_to_nodes[key]:
1238
+ end_addr_to_nodes[key].append(next_node)
1239
+
1240
+ smallest_nodes.pop(nodekey_a, None)
1241
+ smallest_nodes.pop(nodekey_b, None)
1228
1242
 
1229
1243
  self.normalized = True
1230
1244
 
@@ -1235,7 +1249,7 @@ class CFGBase(Analysis):
1235
1249
  smallest_node,
1236
1250
  other_nodes,
1237
1251
  smallest_nodes,
1238
- end_addresses_to_nodes,
1252
+ end_addr_to_nodes,
1239
1253
  ):
1240
1254
  # Break other nodes
1241
1255
  for n in other_nodes:
@@ -1254,8 +1268,8 @@ class CFGBase(Analysis):
1254
1268
  # the logic below is a little convoluted. we check if key exists in either end_address_to_nodes or
1255
1269
  # smallest_nodes, since we don't always add the new node back to end_addresses_to_nodes dict - we only do so
1256
1270
  # when there are more than one node with that key.
1257
- if key in end_addresses_to_nodes:
1258
- new_node = next((i for i in end_addresses_to_nodes[key] if i.addr == n.addr), None)
1271
+ if key in end_addr_to_nodes:
1272
+ new_node = next((i for i in end_addr_to_nodes[key] if i.addr == n.addr), None)
1259
1273
  if new_node is None and key in smallest_nodes and smallest_nodes[key].addr == n.addr:
1260
1274
  new_node = smallest_nodes[key]
1261
1275
 
@@ -1304,8 +1318,10 @@ class CFGBase(Analysis):
1304
1318
 
1305
1319
  # Put the new node into end_addresses list
1306
1320
  if key in smallest_nodes:
1307
- end_addresses_to_nodes[key].add(smallest_nodes[key])
1308
- end_addresses_to_nodes[key].add(new_node)
1321
+ if smallest_nodes[key] not in end_addr_to_nodes[key]:
1322
+ end_addr_to_nodes[key].append(smallest_nodes[key])
1323
+ if new_node not in end_addr_to_nodes[key]:
1324
+ end_addr_to_nodes[key].append(new_node)
1309
1325
  else:
1310
1326
  smallest_nodes[key] = new_node
1311
1327
 
@@ -1936,7 +1952,7 @@ class CFGBase(Analysis):
1936
1952
  # skip empty blocks (that are usually caused by lifting failures)
1937
1953
  continue
1938
1954
  block = func_0.get_block(block_node.addr, block_node.size)
1939
- if block.vex.jumpkind not in ("Ijk_Boring", "Ijk_InvalICache"):
1955
+ if block.vex_nostmt.jumpkind not in ("Ijk_Boring", "Ijk_InvalICache"):
1940
1956
  continue
1941
1957
  # Skip alignment blocks
1942
1958
  if self._is_noop_block(self.project.arch, block):
@@ -2841,6 +2841,11 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
2841
2841
  def _process_irsb_data_refs(self, irsb_addr, data_refs):
2842
2842
  assumption = self._decoding_assumptions.get(irsb_addr & ~1)
2843
2843
  for ref in data_refs:
2844
+ # data_addr + data_size might overflow; we ignore such cases
2845
+ max_addr = 0xFFFF_FFFF if self.project.arch.bits == 32 else 0xFFFF_FFFF_FFFF_FFFF
2846
+ if ref.data_addr + ref.data_size > max_addr:
2847
+ continue
2848
+
2844
2849
  if ref.data_type_str == "integer(store)":
2845
2850
  data_type_str = "integer"
2846
2851
  is_store = True