angr 9.2.135__py3-none-manylinux2014_x86_64.whl → 9.2.137__py3-none-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/__init__.py +3 -7
- angr/analyses/analysis.py +4 -0
- angr/analyses/backward_slice.py +1 -2
- angr/analyses/binary_optimizer.py +3 -4
- angr/analyses/bindiff.py +4 -6
- angr/analyses/boyscout.py +1 -3
- angr/analyses/callee_cleanup_finder.py +4 -4
- angr/analyses/calling_convention/calling_convention.py +6 -4
- angr/analyses/calling_convention/fact_collector.py +10 -3
- angr/analyses/cdg.py +1 -2
- angr/analyses/cfg/cfb.py +1 -3
- angr/analyses/cfg/cfg.py +2 -2
- angr/analyses/cfg/cfg_base.py +40 -68
- angr/analyses/cfg/cfg_emulated.py +1 -104
- angr/analyses/cfg/cfg_fast.py +90 -27
- angr/analyses/cfg/cfg_fast_soot.py +1 -1
- angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
- angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +46 -10
- angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +5 -1
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +65 -14
- angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
- angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +24 -5
- angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +2 -5
- angr/analyses/class_identifier.py +1 -2
- angr/analyses/complete_calling_conventions.py +3 -0
- angr/analyses/congruency_check.py +2 -3
- angr/analyses/data_dep/data_dependency_analysis.py +2 -2
- angr/analyses/ddg.py +1 -4
- angr/analyses/decompiler/ail_simplifier.py +15 -5
- angr/analyses/decompiler/block_simplifier.py +2 -2
- angr/analyses/decompiler/ccall_rewriters/__init__.py +2 -0
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
- angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +69 -0
- angr/analyses/decompiler/clinic.py +119 -72
- angr/analyses/decompiler/condition_processor.py +2 -0
- angr/analyses/decompiler/decompiler.py +1 -0
- angr/analyses/decompiler/dephication/dephication_base.py +2 -0
- angr/analyses/decompiler/dephication/rewriting_engine.py +8 -6
- angr/analyses/decompiler/dephication/seqnode_dephication.py +10 -1
- angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
- angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +2 -2
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +1 -1
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +1 -2
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +1 -1
- angr/analyses/decompiler/sequence_walker.py +6 -2
- angr/analyses/decompiler/ssailification/rewriting.py +11 -1
- angr/analyses/decompiler/ssailification/rewriting_engine.py +56 -19
- angr/analyses/decompiler/ssailification/ssailification.py +13 -3
- angr/analyses/decompiler/ssailification/traversal.py +28 -2
- angr/analyses/decompiler/ssailification/traversal_state.py +6 -1
- angr/analyses/decompiler/structured_codegen/c.py +44 -21
- angr/analyses/decompiler/structuring/phoenix.py +118 -15
- angr/analyses/decompiler/utils.py +113 -8
- angr/analyses/disassembly.py +5 -5
- angr/analyses/fcp/__init__.py +4 -0
- angr/analyses/fcp/fcp.py +429 -0
- angr/analyses/identifier/identify.py +1 -3
- angr/analyses/loopfinder.py +4 -3
- angr/analyses/patchfinder.py +1 -1
- angr/analyses/propagator/engine_base.py +4 -3
- angr/analyses/propagator/propagator.py +14 -53
- angr/analyses/reaching_definitions/function_handler.py +1 -1
- angr/analyses/reassembler.py +1 -2
- angr/analyses/s_liveness.py +5 -1
- angr/analyses/s_propagator.py +26 -7
- angr/analyses/s_reaching_definitions/s_rda_model.py +2 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +20 -1
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +11 -1
- angr/analyses/soot_class_hierarchy.py +1 -2
- angr/analyses/stack_pointer_tracker.py +29 -3
- angr/analyses/static_hooker.py +1 -2
- angr/analyses/typehoon/simple_solver.py +2 -2
- angr/analyses/variable_recovery/engine_ail.py +19 -7
- angr/analyses/variable_recovery/engine_base.py +16 -14
- angr/analyses/variable_recovery/engine_vex.py +2 -2
- angr/analyses/variable_recovery/variable_recovery_fast.py +23 -3
- angr/analyses/veritesting.py +4 -7
- angr/analyses/vfg.py +1 -1
- angr/analyses/vsa_ddg.py +1 -2
- angr/block.py +62 -22
- angr/callable.py +1 -3
- angr/calling_conventions.py +3 -3
- angr/codenode.py +5 -1
- angr/concretization_strategies/__init__.py +1 -83
- angr/concretization_strategies/any.py +2 -1
- angr/concretization_strategies/any_named.py +1 -1
- angr/concretization_strategies/base.py +81 -0
- angr/concretization_strategies/controlled_data.py +2 -1
- angr/concretization_strategies/eval.py +2 -1
- angr/concretization_strategies/logging.py +3 -1
- angr/concretization_strategies/max.py +2 -1
- angr/concretization_strategies/nonzero.py +2 -1
- angr/concretization_strategies/nonzero_range.py +2 -1
- angr/concretization_strategies/norepeats.py +2 -1
- angr/concretization_strategies/norepeats_range.py +2 -1
- angr/concretization_strategies/range.py +2 -1
- angr/concretization_strategies/signed_add.py +2 -1
- angr/concretization_strategies/single.py +2 -1
- angr/concretization_strategies/solutions.py +2 -1
- angr/concretization_strategies/unlimited_range.py +2 -1
- angr/engines/__init__.py +8 -5
- angr/engines/engine.py +3 -5
- angr/engines/failure.py +4 -5
- angr/engines/pcode/emulate.py +1 -1
- angr/engines/pcode/lifter.py +31 -18
- angr/engines/procedure.py +5 -7
- angr/engines/soot/expressions/__init__.py +20 -23
- angr/engines/soot/expressions/base.py +4 -4
- angr/engines/soot/expressions/invoke.py +1 -2
- angr/engines/soot/statements/__init__.py +10 -12
- angr/engines/soot/values/__init__.py +10 -12
- angr/engines/soot/values/arrayref.py +3 -3
- angr/engines/soot/values/instancefieldref.py +3 -2
- angr/engines/successors.py +18 -12
- angr/engines/syscall.py +4 -6
- angr/engines/unicorn.py +3 -2
- angr/engines/vex/claripy/ccall.py +8 -10
- angr/engines/vex/claripy/datalayer.py +4 -5
- angr/engines/vex/lifter.py +9 -6
- angr/exploration_techniques/__init__.py +0 -2
- angr/exploration_techniques/spiller.py +1 -3
- angr/exploration_techniques/stochastic.py +2 -3
- angr/factory.py +3 -9
- angr/flirt/build_sig.py +8 -15
- angr/knowledge_plugins/cfg/cfg_model.py +20 -17
- angr/knowledge_plugins/functions/function.py +70 -79
- angr/knowledge_plugins/functions/function_manager.py +8 -7
- angr/knowledge_plugins/functions/function_parser.py +1 -1
- angr/knowledge_plugins/functions/soot_function.py +21 -24
- angr/knowledge_plugins/propagations/propagation_model.py +4 -5
- angr/knowledge_plugins/propagations/states.py +0 -511
- angr/knowledge_plugins/variables/variable_manager.py +16 -10
- angr/procedures/libc/memcpy.py +4 -4
- angr/procedures/procedure_dict.py +3 -2
- angr/protos/__init__.py +2 -5
- angr/protos/cfg_pb2.py +21 -18
- angr/protos/function_pb2.py +17 -14
- angr/protos/primitives_pb2.py +44 -39
- angr/protos/variables_pb2.py +36 -31
- angr/protos/xrefs_pb2.py +15 -12
- angr/sim_procedure.py +15 -16
- angr/sim_variable.py +13 -1
- angr/simos/__init__.py +2 -0
- angr/simos/javavm.py +4 -6
- angr/simos/xbox.py +32 -0
- angr/state_plugins/__init__.py +0 -2
- angr/state_plugins/callstack.py +4 -4
- angr/state_plugins/cgc.py +3 -2
- angr/state_plugins/gdb.py +6 -5
- angr/state_plugins/globals.py +1 -2
- angr/state_plugins/heap/heap_brk.py +1 -2
- angr/state_plugins/history.py +10 -12
- angr/state_plugins/inspect.py +3 -5
- angr/state_plugins/libc.py +2 -2
- angr/state_plugins/log.py +8 -10
- angr/state_plugins/loop_data.py +1 -2
- angr/state_plugins/posix.py +7 -7
- angr/state_plugins/preconstrainer.py +2 -3
- angr/state_plugins/scratch.py +5 -8
- angr/state_plugins/sim_action.py +3 -3
- angr/state_plugins/solver.py +8 -3
- angr/state_plugins/symbolizer.py +5 -4
- angr/state_plugins/uc_manager.py +3 -3
- angr/state_plugins/unicorn_engine.py +5 -1
- angr/state_plugins/view.py +3 -5
- angr/storage/file.py +3 -5
- angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
- angr/storage/memory_mixins/bvv_conversion_mixin.py +3 -3
- angr/storage/memory_mixins/clouseau_mixin.py +1 -3
- angr/storage/memory_mixins/name_resolution_mixin.py +1 -3
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +13 -15
- angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -22
- angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
- angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
- angr/storage/memory_mixins/paged_memory/privileged_mixin.py +3 -4
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
- angr/storage/memory_mixins/smart_find_mixin.py +1 -1
- angr/storage/memory_mixins/underconstrained_mixin.py +1 -1
- angr/storage/memory_mixins/unwrapper_mixin.py +1 -3
- angr/utils/enums_conv.py +28 -12
- angr/utils/segment_list.py +25 -22
- angr/utils/timing.py +18 -1
- angr/vaults.py +5 -6
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/METADATA +7 -7
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/RECORD +193 -191
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/WHEEL +1 -1
- angr/analyses/propagator/outdated_definition_walker.py +0 -159
- angr/analyses/propagator/tmpvar_finder.py +0 -18
- angr/engines/concrete.py +0 -180
- angr/exploration_techniques/symbion.py +0 -80
- angr/state_plugins/concrete.py +0 -295
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/LICENSE +0 -0
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/entry_points.txt +0 -0
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# pylint:disable=line-too-long,import-outside-toplevel,import-error,multiple-statements,too-many-boolean-expressions
|
|
2
|
+
# ruff: noqa: SIM102
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
from typing import Any, TYPE_CHECKING
|
|
4
5
|
from collections import defaultdict, OrderedDict
|
|
@@ -26,6 +27,7 @@ from angr.analyses.decompiler.utils import (
|
|
|
26
27
|
is_empty_or_label_only_node,
|
|
27
28
|
has_nonlabel_nonphi_statements,
|
|
28
29
|
first_nonlabel_nonphi_statement,
|
|
30
|
+
switch_extract_bitwiseand_jumptable_info,
|
|
29
31
|
)
|
|
30
32
|
from angr.analyses.decompiler.counters.call_counter import AILCallCounter
|
|
31
33
|
from .structurer_nodes import (
|
|
@@ -1045,6 +1047,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1045
1047
|
if r:
|
|
1046
1048
|
return r
|
|
1047
1049
|
jump_tables = self.kb.cfgs["CFGFast"].jump_tables
|
|
1050
|
+
r = self._match_acyclic_switch_cases_address_loaded_from_memory_no_ob_check(
|
|
1051
|
+
node, graph, full_graph, jump_tables
|
|
1052
|
+
)
|
|
1053
|
+
if r:
|
|
1054
|
+
return r
|
|
1048
1055
|
r = self._match_acyclic_switch_cases_address_loaded_from_memory(node, graph, full_graph, jump_tables)
|
|
1049
1056
|
if r:
|
|
1050
1057
|
return r
|
|
@@ -1240,6 +1247,93 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1240
1247
|
|
|
1241
1248
|
return True
|
|
1242
1249
|
|
|
1250
|
+
def _match_acyclic_switch_cases_address_loaded_from_memory_no_ob_check(
|
|
1251
|
+
self, node, graph, full_graph, jump_tables
|
|
1252
|
+
) -> bool:
|
|
1253
|
+
if node.addr not in jump_tables:
|
|
1254
|
+
return False
|
|
1255
|
+
|
|
1256
|
+
try:
|
|
1257
|
+
last_stmt = self.cond_proc.get_last_statement(node)
|
|
1258
|
+
except EmptyBlockNotice:
|
|
1259
|
+
return False
|
|
1260
|
+
if not (isinstance(last_stmt, Jump) and not isinstance(last_stmt.target, Const)):
|
|
1261
|
+
return False
|
|
1262
|
+
|
|
1263
|
+
jump_table = jump_tables[node.addr]
|
|
1264
|
+
if jump_table.type != IndirectJumpType.Jumptable_AddressLoadedFromMemory:
|
|
1265
|
+
return False
|
|
1266
|
+
|
|
1267
|
+
# extract the index expression, lower-, and upper-bounds from the last statement
|
|
1268
|
+
index = switch_extract_bitwiseand_jumptable_info(last_stmt)
|
|
1269
|
+
if not index:
|
|
1270
|
+
return False
|
|
1271
|
+
index_expr, cmp_lb, cmp_ub = index # pylint:disable=unused-variable
|
|
1272
|
+
case_count = cmp_ub - cmp_lb + 1
|
|
1273
|
+
|
|
1274
|
+
# ensure we have the same number of cases
|
|
1275
|
+
if case_count != len(jump_table.jumptable_entries):
|
|
1276
|
+
return False
|
|
1277
|
+
|
|
1278
|
+
# populate whitelist_edges
|
|
1279
|
+
for case_node_addr in jump_table.jumptable_entries:
|
|
1280
|
+
self.whitelist_edges.add((node.addr, case_node_addr))
|
|
1281
|
+
self.switch_case_known_heads.add(node)
|
|
1282
|
+
|
|
1283
|
+
# sanity check: case nodes are successors to node. all case nodes must have at most common one successor
|
|
1284
|
+
node_pred = None
|
|
1285
|
+
if graph.in_degree[node] == 1:
|
|
1286
|
+
node_pred = next(iter(graph.predecessors(node)))
|
|
1287
|
+
|
|
1288
|
+
case_nodes = list(graph.successors(node))
|
|
1289
|
+
|
|
1290
|
+
# case 1: the common successor happens to be directly reachable from node_a (usually as a result of compiler
|
|
1291
|
+
# optimization)
|
|
1292
|
+
# example: touch_touch_no_switch.o:main
|
|
1293
|
+
r = self.switch_case_entry_node_has_common_successor_case_1(graph, jump_table, case_nodes, node_pred)
|
|
1294
|
+
|
|
1295
|
+
# case 2: the common successor is not directly reachable from node_a. this is a more common case.
|
|
1296
|
+
if not r:
|
|
1297
|
+
r |= self.switch_case_entry_node_has_common_successor_case_2(graph, jump_table, case_nodes, node_pred)
|
|
1298
|
+
|
|
1299
|
+
if not r:
|
|
1300
|
+
return False
|
|
1301
|
+
|
|
1302
|
+
case_and_entry_addrs = self._find_case_and_entry_addrs(node, graph, cmp_lb, jump_table)
|
|
1303
|
+
|
|
1304
|
+
cases, node_default, to_remove = self._switch_build_cases(
|
|
1305
|
+
case_and_entry_addrs,
|
|
1306
|
+
node,
|
|
1307
|
+
node,
|
|
1308
|
+
None,
|
|
1309
|
+
graph,
|
|
1310
|
+
full_graph,
|
|
1311
|
+
)
|
|
1312
|
+
|
|
1313
|
+
assert node_default is None
|
|
1314
|
+
switch_end_addr = None
|
|
1315
|
+
|
|
1316
|
+
r = self._make_switch_cases_core(
|
|
1317
|
+
node,
|
|
1318
|
+
index_expr,
|
|
1319
|
+
cases,
|
|
1320
|
+
None,
|
|
1321
|
+
None,
|
|
1322
|
+
last_stmt.ins_addr,
|
|
1323
|
+
to_remove,
|
|
1324
|
+
graph,
|
|
1325
|
+
full_graph,
|
|
1326
|
+
node_a=None,
|
|
1327
|
+
)
|
|
1328
|
+
if not r:
|
|
1329
|
+
return False
|
|
1330
|
+
|
|
1331
|
+
# fully structured into a switch-case. remove node from switch_case_known_heads
|
|
1332
|
+
self.switch_case_known_heads.remove(node)
|
|
1333
|
+
self._switch_handle_gotos(cases, node_default, switch_end_addr)
|
|
1334
|
+
|
|
1335
|
+
return True
|
|
1336
|
+
|
|
1243
1337
|
def _match_acyclic_switch_cases_address_computed(self, node, graph, full_graph, jump_tables) -> bool:
|
|
1244
1338
|
if node.addr not in jump_tables:
|
|
1245
1339
|
return False
|
|
@@ -1333,7 +1427,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1333
1427
|
case_and_entryaddrs: dict[int, int | tuple[int, int | None]],
|
|
1334
1428
|
head_node,
|
|
1335
1429
|
node_a: BaseNode,
|
|
1336
|
-
node_b_addr,
|
|
1430
|
+
node_b_addr: int | None,
|
|
1337
1431
|
graph,
|
|
1338
1432
|
full_graph,
|
|
1339
1433
|
) -> tuple[OrderedDict, Any, set[Any]]:
|
|
@@ -1343,7 +1437,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1343
1437
|
# it is possible that the default node gets duplicated by other analyses and creates a default node (addr.a)
|
|
1344
1438
|
# and a case node (addr.b). The addr.a node is a successor to the head node while the addr.b node is a
|
|
1345
1439
|
# successor to node_a
|
|
1346
|
-
default_node_candidates =
|
|
1440
|
+
default_node_candidates = (
|
|
1441
|
+
[nn for nn in graph.nodes if nn.addr == node_b_addr] if node_b_addr is not None else []
|
|
1442
|
+
)
|
|
1347
1443
|
node_default: BaseNode | None = next(
|
|
1348
1444
|
iter(nn for nn in default_node_candidates if graph.has_edge(head_node, nn)), None
|
|
1349
1445
|
)
|
|
@@ -1355,7 +1451,6 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1355
1451
|
self.replace_nodes(full_graph, node_default, new_node)
|
|
1356
1452
|
node_default = new_node
|
|
1357
1453
|
|
|
1358
|
-
# entry_addrs_set = set(jumptable_entries)
|
|
1359
1454
|
converted_nodes: dict[tuple[int, int | None], Any] = {}
|
|
1360
1455
|
entry_addr_to_ids: defaultdict[tuple[int, int | None], set[int]] = defaultdict(set)
|
|
1361
1456
|
|
|
@@ -1442,7 +1537,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1442
1537
|
head,
|
|
1443
1538
|
cmp_expr,
|
|
1444
1539
|
cases: OrderedDict,
|
|
1445
|
-
node_default_addr: int,
|
|
1540
|
+
node_default_addr: int | None,
|
|
1446
1541
|
node_default,
|
|
1447
1542
|
addr,
|
|
1448
1543
|
to_remove: set,
|
|
@@ -1491,7 +1586,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1491
1586
|
pass
|
|
1492
1587
|
graph.remove_edge(head, node_default)
|
|
1493
1588
|
full_graph.remove_edge(head, node_default)
|
|
1494
|
-
|
|
1589
|
+
elif node_default_addr is not None:
|
|
1495
1590
|
# the default node is not in the current graph, but it might be in the full graph
|
|
1496
1591
|
node_default_in_full_graph = next(iter(nn for nn in full_graph if nn.addr == node_default_addr), None)
|
|
1497
1592
|
if node_default_in_full_graph is not None and full_graph.has_edge(head, node_default_in_full_graph):
|
|
@@ -1536,7 +1631,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1536
1631
|
full_graph.remove_edge(head, out_dst)
|
|
1537
1632
|
|
|
1538
1633
|
# fix full_graph if needed: remove successors that are no longer needed
|
|
1539
|
-
for
|
|
1634
|
+
for _out_src, out_dst in out_edges[1:]:
|
|
1540
1635
|
if out_dst in full_graph and out_dst not in graph and full_graph.in_degree[out_dst] == 0:
|
|
1541
1636
|
full_graph.remove_node(out_dst)
|
|
1542
1637
|
if out_dst in self._region.successors:
|
|
@@ -1570,12 +1665,22 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1570
1665
|
|
|
1571
1666
|
return case_and_entry_addrs
|
|
1572
1667
|
|
|
1573
|
-
def
|
|
1668
|
+
def _is_node_unstructured_switch_case_head(self, node) -> bool:
|
|
1574
1669
|
jump_tables = self.kb.cfgs["CFGFast"].jump_tables
|
|
1575
1670
|
if node.addr in jump_tables:
|
|
1671
|
+
# maybe it has been structured?
|
|
1672
|
+
try:
|
|
1673
|
+
last_stmts = self.cond_proc.get_last_statements(node)
|
|
1674
|
+
except EmptyBlockNotice:
|
|
1675
|
+
return False
|
|
1676
|
+
return len(last_stmts) == 1 and isinstance(last_stmts[0], Jump)
|
|
1677
|
+
return False
|
|
1678
|
+
|
|
1679
|
+
def _is_switch_cases_address_loaded_from_memory_head_or_jumpnode(self, graph, node) -> bool:
|
|
1680
|
+
if self._is_node_unstructured_switch_case_head(node):
|
|
1576
1681
|
return True
|
|
1577
1682
|
for succ in graph.successors(node):
|
|
1578
|
-
if succ
|
|
1683
|
+
if self._is_node_unstructured_switch_case_head(succ):
|
|
1579
1684
|
return True
|
|
1580
1685
|
return node in self.switch_case_known_heads
|
|
1581
1686
|
|
|
@@ -1634,13 +1739,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1634
1739
|
)
|
|
1635
1740
|
):
|
|
1636
1741
|
# potentially ITE
|
|
1637
|
-
jump_tables = self.kb.cfgs["CFGFast"].jump_tables
|
|
1638
|
-
|
|
1639
1742
|
if (
|
|
1640
1743
|
full_graph.in_degree[left] == 1
|
|
1641
1744
|
and full_graph.in_degree[right] == 1
|
|
1642
|
-
and
|
|
1643
|
-
and
|
|
1745
|
+
and not self._is_node_unstructured_switch_case_head(left)
|
|
1746
|
+
and not self._is_node_unstructured_switch_case_head(right)
|
|
1644
1747
|
):
|
|
1645
1748
|
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
1646
1749
|
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
@@ -1681,9 +1784,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1681
1784
|
left_succs, right_succs = right_succs, left_succs
|
|
1682
1785
|
if left in graph and not left_succs and full_graph.in_degree[left] == 1 and right in graph:
|
|
1683
1786
|
# potentially If-Then
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1787
|
+
if not self._is_node_unstructured_switch_case_head(
|
|
1788
|
+
left
|
|
1789
|
+
) and not self._is_node_unstructured_switch_case_head(right):
|
|
1687
1790
|
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
1688
1791
|
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
1689
1792
|
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right):
|
|
@@ -40,7 +40,7 @@ def remove_last_statement(node):
|
|
|
40
40
|
elif type(node) is LoopNode:
|
|
41
41
|
stmt = remove_last_statement(node.sequence_node)
|
|
42
42
|
else:
|
|
43
|
-
raise NotImplementedError
|
|
43
|
+
raise NotImplementedError(type(node))
|
|
44
44
|
|
|
45
45
|
return stmt
|
|
46
46
|
|
|
@@ -69,7 +69,7 @@ def remove_last_statements(node) -> bool:
|
|
|
69
69
|
return r
|
|
70
70
|
if type(node) is LoopNode:
|
|
71
71
|
return remove_last_statements(node.sequence_node)
|
|
72
|
-
raise NotImplementedError
|
|
72
|
+
raise NotImplementedError(type(node))
|
|
73
73
|
|
|
74
74
|
|
|
75
75
|
def append_statement(node, stmt):
|
|
@@ -83,16 +83,16 @@ def append_statement(node, stmt):
|
|
|
83
83
|
if node.nodes:
|
|
84
84
|
append_statement(node.nodes[-1], stmt)
|
|
85
85
|
else:
|
|
86
|
-
raise NotImplementedError
|
|
86
|
+
raise NotImplementedError("MultiNode without nodes")
|
|
87
87
|
return
|
|
88
88
|
if type(node) is SequenceNode:
|
|
89
89
|
if node.nodes:
|
|
90
90
|
append_statement(node.nodes[-1], stmt)
|
|
91
91
|
else:
|
|
92
|
-
raise NotImplementedError
|
|
92
|
+
raise NotImplementedError("SequenceNode without nodes")
|
|
93
93
|
return
|
|
94
94
|
|
|
95
|
-
raise NotImplementedError
|
|
95
|
+
raise NotImplementedError(type(node))
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
def replace_last_statement(node, old_stmt, new_stmt):
|
|
@@ -118,7 +118,7 @@ def replace_last_statement(node, old_stmt, new_stmt):
|
|
|
118
118
|
replace_last_statement(node.false_node, old_stmt, new_stmt)
|
|
119
119
|
return
|
|
120
120
|
|
|
121
|
-
raise NotImplementedError
|
|
121
|
+
raise NotImplementedError(type(node))
|
|
122
122
|
|
|
123
123
|
|
|
124
124
|
def extract_jump_targets(stmt):
|
|
@@ -175,6 +175,111 @@ def switch_extract_cmp_bounds(last_stmt: ailment.Stmt.ConditionalJump) -> tuple[
|
|
|
175
175
|
return None
|
|
176
176
|
|
|
177
177
|
|
|
178
|
+
def switch_extract_bitwiseand_jumptable_info(last_stmt: ailment.Stmt.Jump) -> tuple[Any, int, int] | None:
|
|
179
|
+
"""
|
|
180
|
+
Check the last statement of the switch-case header node (whose address is loaded from a jump table and computed
|
|
181
|
+
using an index) and extract necessary information for rebuilding the switch-case construct.
|
|
182
|
+
|
|
183
|
+
An example of the statement:
|
|
184
|
+
|
|
185
|
+
Goto(Conv(32->s64, (
|
|
186
|
+
Load(addr=(0x4530e4<64> + (Conv(32->64, (Conv(64->32, vvar_287{reg 32}) & 0x3<32>)) * 0x4<64>)),
|
|
187
|
+
size=4, endness=Iend_LE) + 0x4530e4<32>))
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
:param last_stmt: The last statement of the switch-case header node.
|
|
191
|
+
:return: A tuple of (index expression, lower bound, upper bound), or None
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
if not isinstance(last_stmt, ailment.Stmt.Jump):
|
|
195
|
+
return None
|
|
196
|
+
|
|
197
|
+
# unpack the target expression
|
|
198
|
+
target = last_stmt.target
|
|
199
|
+
jump_addr_offset = None
|
|
200
|
+
jumptable_load_addr = None
|
|
201
|
+
while True:
|
|
202
|
+
if isinstance(target, ailment.Expr.Convert) and (
|
|
203
|
+
(target.from_bits == 32 and target.to_bits == 64) or (target.from_bits == 16 and target.to_bits == 32)
|
|
204
|
+
):
|
|
205
|
+
target = target.operand
|
|
206
|
+
continue
|
|
207
|
+
if isinstance(target, ailment.Expr.BinaryOp) and target.op == "Add":
|
|
208
|
+
if isinstance(target.operands[0], ailment.Expr.Const) and isinstance(target.operands[1], ailment.Expr.Load):
|
|
209
|
+
jump_addr_offset = target.operands[0]
|
|
210
|
+
jumptable_load_addr = target.operands[1].addr
|
|
211
|
+
break
|
|
212
|
+
if isinstance(target.operands[1], ailment.Expr.Const) and isinstance(target.operands[0], ailment.Expr.Load):
|
|
213
|
+
jump_addr_offset = target.operands[1]
|
|
214
|
+
jumptable_load_addr = target.operands[0].addr
|
|
215
|
+
break
|
|
216
|
+
return None
|
|
217
|
+
if isinstance(target, ailment.Expr.Const):
|
|
218
|
+
return None
|
|
219
|
+
break
|
|
220
|
+
|
|
221
|
+
if jump_addr_offset is None or jumptable_load_addr is None:
|
|
222
|
+
return None
|
|
223
|
+
|
|
224
|
+
# parse jumptable_load_addr
|
|
225
|
+
jumptable_offset = None
|
|
226
|
+
jumptable_base_addr = None
|
|
227
|
+
if isinstance(jumptable_load_addr, ailment.Expr.BinaryOp) and jumptable_load_addr.op == "Add":
|
|
228
|
+
if isinstance(jumptable_load_addr.operands[0], ailment.Expr.Const):
|
|
229
|
+
jumptable_base_addr = jumptable_load_addr.operands[0]
|
|
230
|
+
jumptable_offset = jumptable_load_addr.operands[1]
|
|
231
|
+
elif isinstance(jumptable_load_addr.operands[1], ailment.Expr.Const):
|
|
232
|
+
jumptable_offset = jumptable_load_addr.operands[0]
|
|
233
|
+
jumptable_base_addr = jumptable_load_addr.operands[1]
|
|
234
|
+
|
|
235
|
+
if jumptable_offset is None or jumptable_base_addr is None:
|
|
236
|
+
return None
|
|
237
|
+
|
|
238
|
+
# parse jumptable_offset
|
|
239
|
+
expr = jumptable_offset
|
|
240
|
+
coeff = None
|
|
241
|
+
index_expr = None
|
|
242
|
+
lb = None
|
|
243
|
+
ub = None
|
|
244
|
+
while expr is not None:
|
|
245
|
+
if isinstance(expr, ailment.Expr.BinaryOp):
|
|
246
|
+
if expr.op == "Mul":
|
|
247
|
+
if isinstance(expr.operands[1], ailment.Expr.Const):
|
|
248
|
+
coeff = expr.operands[1].value
|
|
249
|
+
expr = expr.operands[0]
|
|
250
|
+
elif isinstance(expr.operands[0], ailment.Expr.Const):
|
|
251
|
+
coeff = expr.operands[0].value
|
|
252
|
+
expr = expr.operands[1]
|
|
253
|
+
else:
|
|
254
|
+
return None
|
|
255
|
+
elif expr.op == "And":
|
|
256
|
+
masks = {0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF}
|
|
257
|
+
if isinstance(expr.operands[1], ailment.Expr.Const) and expr.operands[1].value in masks:
|
|
258
|
+
lb = 0
|
|
259
|
+
ub = expr.operands[1].value
|
|
260
|
+
index_expr = expr
|
|
261
|
+
break
|
|
262
|
+
if isinstance(expr.operands[0], ailment.Expr.Const) and expr.operands[1].value in masks:
|
|
263
|
+
lb = 0
|
|
264
|
+
ub = expr.operands[0].value
|
|
265
|
+
index_expr = expr
|
|
266
|
+
break
|
|
267
|
+
return None
|
|
268
|
+
else:
|
|
269
|
+
return None
|
|
270
|
+
elif isinstance(expr, ailment.Expr.Convert):
|
|
271
|
+
if expr.is_signed is False:
|
|
272
|
+
expr = expr.operand
|
|
273
|
+
else:
|
|
274
|
+
return None
|
|
275
|
+
else:
|
|
276
|
+
break
|
|
277
|
+
|
|
278
|
+
if coeff is not None and index_expr is not None and lb is not None and ub is not None:
|
|
279
|
+
return index_expr, lb, ub
|
|
280
|
+
return None
|
|
281
|
+
|
|
282
|
+
|
|
178
283
|
def get_ast_subexprs(claripy_ast):
|
|
179
284
|
queue = [claripy_ast]
|
|
180
285
|
while queue:
|
|
@@ -267,9 +372,9 @@ def insert_node(parent, insert_location: str, node, node_idx: int | tuple[int] |
|
|
|
267
372
|
parent.sequence_node = SequenceNode(parent.sequence_node.addr, nodes=[parent.sequence_node])
|
|
268
373
|
insert_node(parent.sequence_node, insert_location, node, node_idx)
|
|
269
374
|
else:
|
|
270
|
-
raise NotImplementedError
|
|
375
|
+
raise NotImplementedError(label)
|
|
271
376
|
else:
|
|
272
|
-
raise NotImplementedError
|
|
377
|
+
raise NotImplementedError(type(parent))
|
|
273
378
|
|
|
274
379
|
|
|
275
380
|
def _merge_ail_nodes(graph, node_a: ailment.Block, node_b: ailment.Block) -> ailment.Block:
|
angr/analyses/disassembly.py
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
2
4
|
import logging
|
|
3
5
|
from collections import defaultdict
|
|
4
|
-
from typing import Union, Any
|
|
5
6
|
from collections.abc import Sequence
|
|
7
|
+
from typing import Union, Any
|
|
6
8
|
|
|
7
9
|
import pyvex
|
|
8
10
|
import archinfo
|
|
9
|
-
from angr.knowledge_plugins import Function
|
|
10
11
|
|
|
11
12
|
from . import Analysis
|
|
12
13
|
|
|
14
|
+
from angr.analyses import AnalysesHub
|
|
13
15
|
from angr.errors import AngrTypeError
|
|
16
|
+
from angr.knowledge_plugins import Function
|
|
14
17
|
from angr.utils.library import get_cpp_function_name
|
|
15
18
|
from angr.utils.formatting import ansi_color_enabled, ansi_color, add_edge_to_buffer
|
|
16
19
|
from angr.block import DisassemblerInsn, CapstoneInsn, SootBlockNode
|
|
17
20
|
from angr.codenode import BlockNode
|
|
18
21
|
from .disassembly_utils import decode_instruction
|
|
19
|
-
import contextlib
|
|
20
22
|
|
|
21
23
|
try:
|
|
22
24
|
from angr.engines import pcode
|
|
@@ -1295,6 +1297,4 @@ class Disassembly(Analysis):
|
|
|
1295
1297
|
return "\n".join(buf)
|
|
1296
1298
|
|
|
1297
1299
|
|
|
1298
|
-
from angr.analyses import AnalysesHub
|
|
1299
|
-
|
|
1300
1300
|
AnalysesHub.register_default("Disassembly", Disassembly)
|