angr 9.2.138__py3-none-manylinux2014_x86_64.whl → 9.2.140__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/calling_convention/calling_convention.py +48 -21
- angr/analyses/calling_convention/fact_collector.py +59 -12
- angr/analyses/calling_convention/utils.py +2 -2
- angr/analyses/cfg/cfg_base.py +13 -0
- angr/analyses/cfg/cfg_fast.py +23 -4
- angr/analyses/decompiler/ail_simplifier.py +79 -53
- angr/analyses/decompiler/block_simplifier.py +0 -2
- angr/analyses/decompiler/callsite_maker.py +80 -14
- angr/analyses/decompiler/clinic.py +99 -80
- angr/analyses/decompiler/condition_processor.py +2 -2
- angr/analyses/decompiler/decompiler.py +19 -7
- angr/analyses/decompiler/dephication/rewriting_engine.py +16 -7
- angr/analyses/decompiler/expression_narrower.py +1 -1
- angr/analyses/decompiler/optimization_passes/__init__.py +3 -0
- angr/analyses/decompiler/optimization_passes/condition_constprop.py +149 -0
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +8 -7
- angr/analyses/decompiler/optimization_passes/deadblock_remover.py +12 -3
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +21 -13
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +21 -12
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +17 -9
- angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +7 -10
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +12 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +61 -25
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +50 -1
- angr/analyses/decompiler/presets/fast.py +2 -0
- angr/analyses/decompiler/presets/full.py +2 -0
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +259 -108
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +28 -9
- angr/analyses/decompiler/ssailification/rewriting_engine.py +20 -2
- angr/analyses/decompiler/ssailification/traversal_engine.py +4 -3
- angr/analyses/decompiler/structured_codegen/c.py +10 -3
- angr/analyses/decompiler/structuring/dream.py +28 -19
- angr/analyses/decompiler/structuring/phoenix.py +253 -89
- angr/analyses/decompiler/structuring/recursive_structurer.py +1 -0
- angr/analyses/decompiler/structuring/structurer_base.py +121 -46
- angr/analyses/decompiler/structuring/structurer_nodes.py +6 -1
- angr/analyses/decompiler/utils.py +60 -1
- angr/analyses/deobfuscator/api_obf_finder.py +13 -5
- angr/analyses/deobfuscator/api_obf_type2_finder.py +166 -0
- angr/analyses/deobfuscator/string_obf_finder.py +105 -18
- angr/analyses/forward_analysis/forward_analysis.py +1 -1
- angr/analyses/propagator/top_checker_mixin.py +6 -6
- angr/analyses/reaching_definitions/__init__.py +2 -1
- angr/analyses/reaching_definitions/dep_graph.py +1 -12
- angr/analyses/reaching_definitions/engine_vex.py +36 -31
- angr/analyses/reaching_definitions/function_handler.py +15 -2
- angr/analyses/reaching_definitions/rd_state.py +1 -37
- angr/analyses/reaching_definitions/reaching_definitions.py +13 -24
- angr/analyses/s_propagator.py +129 -87
- angr/analyses/s_reaching_definitions/s_rda_model.py +7 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +2 -2
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +3 -1
- angr/analyses/stack_pointer_tracker.py +36 -22
- angr/analyses/typehoon/simple_solver.py +45 -7
- angr/analyses/typehoon/typeconsts.py +18 -5
- angr/analyses/variable_recovery/engine_ail.py +1 -1
- angr/analyses/variable_recovery/engine_base.py +62 -67
- angr/analyses/variable_recovery/engine_vex.py +1 -1
- angr/analyses/variable_recovery/irsb_scanner.py +2 -2
- angr/block.py +69 -107
- angr/callable.py +14 -7
- angr/calling_conventions.py +81 -10
- angr/distributed/__init__.py +1 -1
- angr/engines/__init__.py +7 -8
- angr/engines/engine.py +3 -138
- angr/engines/failure.py +2 -2
- angr/engines/hook.py +2 -2
- angr/engines/light/engine.py +5 -10
- angr/engines/pcode/emulate.py +2 -2
- angr/engines/pcode/engine.py +2 -14
- angr/engines/pcode/lifter.py +2 -2
- angr/engines/procedure.py +2 -2
- angr/engines/soot/engine.py +2 -2
- angr/engines/soot/statements/switch.py +1 -1
- angr/engines/successors.py +123 -17
- angr/engines/syscall.py +2 -2
- angr/engines/unicorn.py +3 -3
- angr/engines/vex/heavy/heavy.py +3 -15
- angr/engines/vex/lifter.py +2 -2
- angr/engines/vex/light/light.py +2 -2
- angr/factory.py +4 -19
- angr/knowledge_plugins/cfg/cfg_model.py +3 -2
- angr/knowledge_plugins/key_definitions/atoms.py +8 -4
- angr/knowledge_plugins/key_definitions/live_definitions.py +41 -103
- angr/knowledge_plugins/labels.py +2 -2
- angr/knowledge_plugins/obfuscations.py +1 -0
- angr/knowledge_plugins/xrefs/xref_manager.py +4 -0
- angr/sim_type.py +19 -17
- angr/state_plugins/plugin.py +19 -4
- angr/storage/memory_mixins/memory_mixin.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +10 -5
- angr/utils/ssa/__init__.py +119 -4
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/METADATA +6 -6
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/RECORD +100 -98
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/LICENSE +0 -0
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/WHEEL +0 -0
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/entry_points.txt +0 -0
- {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/top_level.txt +0 -0
|
@@ -27,6 +27,7 @@ from ailment.expression import (
|
|
|
27
27
|
from angr.analyses.s_propagator import SPropagatorAnalysis
|
|
28
28
|
from angr.analyses.s_reaching_definitions import SRDAModel
|
|
29
29
|
from angr.utils.ail import is_phi_assignment, HasExprWalker
|
|
30
|
+
from angr.utils.ssa import has_call_in_between_stmts, has_store_stmt_in_between_stmts, has_load_expr_in_between_stmts
|
|
30
31
|
from angr.code_location import CodeLocation, ExternalCodeLocation
|
|
31
32
|
from angr.sim_variable import SimStackVariable, SimMemoryVariable, SimVariable
|
|
32
33
|
from angr.knowledge_plugins.propagations.states import Equivalence
|
|
@@ -102,7 +103,7 @@ class AILSimplifier(Analysis):
|
|
|
102
103
|
self.func = func
|
|
103
104
|
self.func_graph = func_graph if func_graph is not None else func.graph
|
|
104
105
|
self._reaching_definitions: SRDAModel | None = None
|
|
105
|
-
self._propagator = None
|
|
106
|
+
self._propagator: SPropagatorAnalysis | None = None
|
|
106
107
|
|
|
107
108
|
self._remove_dead_memdefs = remove_dead_memdefs
|
|
108
109
|
self._stack_arg_offsets = stack_arg_offsets
|
|
@@ -117,6 +118,7 @@ class AILSimplifier(Analysis):
|
|
|
117
118
|
self._removed_vvar_ids = removed_vvar_ids if removed_vvar_ids is not None else set()
|
|
118
119
|
self._arg_vvars = arg_vvars
|
|
119
120
|
self._avoid_vvar_ids = avoid_vvar_ids
|
|
121
|
+
self._propagator_dead_vvar_ids: set[int] = set()
|
|
120
122
|
|
|
121
123
|
self._calls_to_remove: set[CodeLocation] = set()
|
|
122
124
|
self._assignments_to_remove: set[CodeLocation] = set()
|
|
@@ -231,6 +233,7 @@ class AILSimplifier(Analysis):
|
|
|
231
233
|
only_consts=self._only_consts,
|
|
232
234
|
)
|
|
233
235
|
self._propagator = prop
|
|
236
|
+
self._propagator_dead_vvar_ids = prop.dead_vvar_ids
|
|
234
237
|
return prop
|
|
235
238
|
|
|
236
239
|
def _compute_equivalence(self) -> set[Equivalence]:
|
|
@@ -247,6 +250,9 @@ class AILSimplifier(Analysis):
|
|
|
247
250
|
if isinstance(stmt.ret_expr, (VirtualVariable, Load)):
|
|
248
251
|
codeloc = CodeLocation(block.addr, stmt_idx, block_idx=block.idx, ins_addr=stmt.ins_addr)
|
|
249
252
|
equivalence.add(Equivalence(codeloc, stmt.ret_expr, stmt))
|
|
253
|
+
elif isinstance(stmt.fp_ret_expr, (VirtualVariable, Load)):
|
|
254
|
+
codeloc = CodeLocation(block.addr, stmt_idx, block_idx=block.idx, ins_addr=stmt.ins_addr)
|
|
255
|
+
equivalence.add(Equivalence(codeloc, stmt.fp_ret_expr, stmt))
|
|
250
256
|
elif (
|
|
251
257
|
isinstance(stmt, Store)
|
|
252
258
|
and isinstance(stmt.size, int)
|
|
@@ -287,7 +293,7 @@ class AILSimplifier(Analysis):
|
|
|
287
293
|
|
|
288
294
|
narrowed = False
|
|
289
295
|
|
|
290
|
-
addr_and_idx_to_block: dict[tuple[int, int], Block] = {}
|
|
296
|
+
addr_and_idx_to_block: dict[tuple[int, int | None], Block] = {}
|
|
291
297
|
for block in self.func_graph.nodes():
|
|
292
298
|
addr_and_idx_to_block[(block.addr, block.idx)] = block
|
|
293
299
|
|
|
@@ -419,6 +425,7 @@ class AILSimplifier(Analysis):
|
|
|
419
425
|
return ExprNarrowingInfo(False)
|
|
420
426
|
|
|
421
427
|
block = self.blocks.get(old_block, old_block)
|
|
428
|
+
assert loc.stmt_idx is not None
|
|
422
429
|
if loc.stmt_idx >= len(block.statements):
|
|
423
430
|
# missing a statement for whatever reason
|
|
424
431
|
return ExprNarrowingInfo(False)
|
|
@@ -546,14 +553,23 @@ class AILSimplifier(Analysis):
|
|
|
546
553
|
return None, None
|
|
547
554
|
return expr.size, ("expr", (expr,))
|
|
548
555
|
|
|
549
|
-
|
|
556
|
+
ops = walker.operations
|
|
557
|
+
first_op = ops[0]
|
|
558
|
+
if isinstance(first_op, BinaryOp) and first_op.op in {"Add", "Sub"}:
|
|
559
|
+
# expr + x
|
|
560
|
+
ops = ops[1:]
|
|
561
|
+
if not ops:
|
|
562
|
+
if expr is None:
|
|
563
|
+
return None, None
|
|
564
|
+
return expr.size, ("expr", (expr,))
|
|
565
|
+
first_op = ops[0]
|
|
550
566
|
if isinstance(first_op, Convert) and first_op.to_bits >= self.project.arch.byte_width:
|
|
551
567
|
# we need at least one byte!
|
|
552
568
|
return first_op.to_bits // self.project.arch.byte_width, ("convert", (first_op,))
|
|
553
569
|
if isinstance(first_op, BinaryOp):
|
|
554
570
|
second_op = None
|
|
555
|
-
if len(
|
|
556
|
-
second_op =
|
|
571
|
+
if len(ops) >= 2:
|
|
572
|
+
second_op = ops[1]
|
|
557
573
|
if (
|
|
558
574
|
first_op.op == "And"
|
|
559
575
|
and isinstance(first_op.operands[1], Const)
|
|
@@ -618,9 +634,9 @@ class AILSimplifier(Analysis):
|
|
|
618
634
|
block = blocks_by_addr_and_idx[(block_addr, block_idx)]
|
|
619
635
|
|
|
620
636
|
# only replace loads if there are stack arguments in this block
|
|
621
|
-
replace_loads = insn_addrs_using_stack_args is not None and
|
|
622
|
-
stmt.ins_addr for stmt in block.statements
|
|
623
|
-
|
|
637
|
+
replace_loads: bool = insn_addrs_using_stack_args is not None and bool(
|
|
638
|
+
{stmt.ins_addr for stmt in block.statements}.intersection(insn_addrs_using_stack_args)
|
|
639
|
+
)
|
|
624
640
|
|
|
625
641
|
# remove virtual variables in the avoid list
|
|
626
642
|
if self._avoid_vvar_ids:
|
|
@@ -657,7 +673,7 @@ class AILSimplifier(Analysis):
|
|
|
657
673
|
if not equivalence:
|
|
658
674
|
return simplified
|
|
659
675
|
|
|
660
|
-
addr_and_idx_to_block: dict[tuple[int, int], Block] = {}
|
|
676
|
+
addr_and_idx_to_block: dict[tuple[int, int | None], Block] = {}
|
|
661
677
|
for block in self.func_graph.nodes():
|
|
662
678
|
addr_and_idx_to_block[(block.addr, block.idx)] = block
|
|
663
679
|
|
|
@@ -938,6 +954,8 @@ class AILSimplifier(Analysis):
|
|
|
938
954
|
for use_loc in all_use_locs:
|
|
939
955
|
if use_loc == eq.codeloc:
|
|
940
956
|
continue
|
|
957
|
+
assert use_loc.block_addr is not None
|
|
958
|
+
assert use_loc.stmt_idx is not None
|
|
941
959
|
block = addr_and_idx_to_block[(use_loc.block_addr, use_loc.block_idx)]
|
|
942
960
|
stmt = block.statements[use_loc.stmt_idx]
|
|
943
961
|
if isinstance(stmt, Assignment) or (isinstance(replace_with, Load) and isinstance(stmt, Store)):
|
|
@@ -949,11 +967,15 @@ class AILSimplifier(Analysis):
|
|
|
949
967
|
|
|
950
968
|
remove_initial_assignment = False # expression folding will take care of it
|
|
951
969
|
|
|
970
|
+
assert replace_with is not None
|
|
971
|
+
|
|
952
972
|
if any(not isinstance(use_and_expr[1], VirtualVariable) for _, use_and_expr in all_uses_with_def):
|
|
953
973
|
# if any of the uses are phi assignments, we skip
|
|
954
974
|
used_in_phi_assignment = False
|
|
955
975
|
for _, use_and_expr in all_uses_with_def:
|
|
956
976
|
u = use_and_expr[0]
|
|
977
|
+
assert u.block_addr is not None
|
|
978
|
+
assert u.stmt_idx is not None
|
|
957
979
|
block = addr_and_idx_to_block[(u.block_addr, u.block_idx)]
|
|
958
980
|
stmt = block.statements[u.stmt_idx]
|
|
959
981
|
if is_phi_assignment(stmt):
|
|
@@ -1116,13 +1138,14 @@ class AILSimplifier(Analysis):
|
|
|
1116
1138
|
In such cases, the one-use expression folder in RegionSimplifier will perform this transformation.
|
|
1117
1139
|
"""
|
|
1118
1140
|
|
|
1141
|
+
# pylint:disable=unreachable
|
|
1119
1142
|
simplified = False
|
|
1120
1143
|
|
|
1121
1144
|
equivalence = self._compute_equivalence()
|
|
1122
1145
|
if not equivalence:
|
|
1123
1146
|
return simplified
|
|
1124
1147
|
|
|
1125
|
-
addr_and_idx_to_block: dict[tuple[int, int], Block] = {}
|
|
1148
|
+
addr_and_idx_to_block: dict[tuple[int, int | None], Block] = {}
|
|
1126
1149
|
for block in self.func_graph.nodes():
|
|
1127
1150
|
addr_and_idx_to_block[(block.addr, block.idx)] = block
|
|
1128
1151
|
|
|
@@ -1160,6 +1183,8 @@ class AILSimplifier(Analysis):
|
|
|
1160
1183
|
),
|
|
1161
1184
|
eq.codeloc,
|
|
1162
1185
|
)
|
|
1186
|
+
assert the_def.codeloc.block_addr is not None
|
|
1187
|
+
assert the_def.codeloc.stmt_idx is not None
|
|
1163
1188
|
|
|
1164
1189
|
all_uses: set[tuple[CodeLocation, Any]] = set(rd.get_vvar_uses_with_expr(the_def.atom))
|
|
1165
1190
|
|
|
@@ -1168,6 +1193,8 @@ class AILSimplifier(Analysis):
|
|
|
1168
1193
|
u, used_expr = next(iter(all_uses))
|
|
1169
1194
|
if used_expr is None:
|
|
1170
1195
|
continue
|
|
1196
|
+
assert u.block_addr is not None
|
|
1197
|
+
assert u.stmt_idx is not None
|
|
1171
1198
|
|
|
1172
1199
|
if u in def_locations_to_remove:
|
|
1173
1200
|
# this use site has been altered by previous folding attempts. the corresponding statement will be
|
|
@@ -1188,41 +1215,28 @@ class AILSimplifier(Analysis):
|
|
|
1188
1215
|
if u.block_addr not in {b.addr for b in super_node_blocks}:
|
|
1189
1216
|
continue
|
|
1190
1217
|
|
|
1191
|
-
#
|
|
1192
|
-
#
|
|
1193
|
-
|
|
1194
|
-
#
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
# if usesite_expr_uses != defsite_expr_uses:
|
|
1214
|
-
# # special case: ok if this atom is assigned to at the def site and has not been overwritten
|
|
1215
|
-
# if len(usesite_expr_uses) == 1:
|
|
1216
|
-
# usesite_expr_use = next(iter(usesite_expr_uses))
|
|
1217
|
-
# if usesite_expr_use.atom == defsite_expr_atom and (
|
|
1218
|
-
# usesite_expr_use.codeloc == the_def.codeloc
|
|
1219
|
-
# or usesite_expr_use.codeloc.block_addr == call_addr
|
|
1220
|
-
# ):
|
|
1221
|
-
# continue
|
|
1222
|
-
# usesite_expr_def_outdated = True
|
|
1223
|
-
# break
|
|
1224
|
-
# if usesite_expr_def_outdated:
|
|
1225
|
-
# continue
|
|
1218
|
+
# ensure there are no other calls between the def site and the use site.
|
|
1219
|
+
# this is because we do not want to alter the order of calls.
|
|
1220
|
+
u_inclusive = CodeLocation(u.block_addr, u.stmt_idx + 1, block_idx=u.block_idx)
|
|
1221
|
+
# note that the target statement being a store is fine
|
|
1222
|
+
if (
|
|
1223
|
+
has_call_in_between_stmts(
|
|
1224
|
+
self.func_graph,
|
|
1225
|
+
addr_and_idx_to_block,
|
|
1226
|
+
the_def.codeloc,
|
|
1227
|
+
u_inclusive,
|
|
1228
|
+
skip_if_contains_vvar=the_def.atom.varid,
|
|
1229
|
+
)
|
|
1230
|
+
or has_store_stmt_in_between_stmts(self.func_graph, addr_and_idx_to_block, the_def.codeloc, u)
|
|
1231
|
+
or has_load_expr_in_between_stmts(
|
|
1232
|
+
self.func_graph,
|
|
1233
|
+
addr_and_idx_to_block,
|
|
1234
|
+
the_def.codeloc,
|
|
1235
|
+
u_inclusive,
|
|
1236
|
+
skip_if_contains_vvar=the_def.atom.varid,
|
|
1237
|
+
)
|
|
1238
|
+
):
|
|
1239
|
+
continue
|
|
1226
1240
|
|
|
1227
1241
|
# check if there are any calls in between the def site and the use site
|
|
1228
1242
|
if self._count_calls_in_supernodeblocks(super_node_blocks, the_def.codeloc, u) > 0:
|
|
@@ -1308,8 +1322,8 @@ class AILSimplifier(Analysis):
|
|
|
1308
1322
|
# keeping tracking of statements to remove and statements (as well as dead vvars) to keep allows us to handle
|
|
1309
1323
|
# cases where a statement defines more than one atoms, e.g., a call statement that defines both the return
|
|
1310
1324
|
# value and the floating-point return value.
|
|
1311
|
-
stmts_to_remove_per_block: dict[tuple[int, int], set[int]] = defaultdict(set)
|
|
1312
|
-
stmts_to_keep_per_block: dict[tuple[int, int], set[int]] = defaultdict(set)
|
|
1325
|
+
stmts_to_remove_per_block: dict[tuple[int, int | None], set[int]] = defaultdict(set)
|
|
1326
|
+
stmts_to_keep_per_block: dict[tuple[int, int | None], set[int]] = defaultdict(set)
|
|
1313
1327
|
dead_vvar_ids: set[int] = set()
|
|
1314
1328
|
|
|
1315
1329
|
# Find all statements that should be removed
|
|
@@ -1326,13 +1340,17 @@ class AILSimplifier(Analysis):
|
|
|
1326
1340
|
if isinstance(def_.atom, atoms.MemoryLocation) and isinstance(def_.atom.addr, int):
|
|
1327
1341
|
continue
|
|
1328
1342
|
if isinstance(def_.atom, atoms.VirtualVariable):
|
|
1329
|
-
if def_.atom.
|
|
1343
|
+
if def_.atom.varid in self._propagator_dead_vvar_ids:
|
|
1344
|
+
# we are definitely removing this variable if it has no uses
|
|
1345
|
+
uses = rd.get_vvar_uses(def_.atom)
|
|
1346
|
+
elif def_.atom.was_stack:
|
|
1330
1347
|
if not self._remove_dead_memdefs:
|
|
1331
1348
|
if rd.is_phi_vvar_id(def_.atom.varid):
|
|
1332
1349
|
# we always remove unused phi variables
|
|
1333
1350
|
pass
|
|
1334
1351
|
elif stackarg_offsets is not None:
|
|
1335
1352
|
# we always remove definitions for stack arguments
|
|
1353
|
+
assert def_.atom.stack_offset is not None
|
|
1336
1354
|
if (def_.atom.stack_offset & mask) not in stackarg_offsets:
|
|
1337
1355
|
continue
|
|
1338
1356
|
else:
|
|
@@ -1353,10 +1371,15 @@ class AILSimplifier(Analysis):
|
|
|
1353
1371
|
dead_vvar_ids.add(def_.atom.varid)
|
|
1354
1372
|
|
|
1355
1373
|
if not isinstance(def_.codeloc, ExternalCodeLocation):
|
|
1374
|
+
assert def_.codeloc.block_addr is not None
|
|
1375
|
+
assert def_.codeloc.stmt_idx is not None
|
|
1356
1376
|
stmts_to_remove_per_block[(def_.codeloc.block_addr, def_.codeloc.block_idx)].add(
|
|
1357
1377
|
def_.codeloc.stmt_idx
|
|
1358
1378
|
)
|
|
1359
1379
|
else:
|
|
1380
|
+
if not isinstance(def_.codeloc, ExternalCodeLocation):
|
|
1381
|
+
assert def_.codeloc.block_addr is not None
|
|
1382
|
+
assert def_.codeloc.stmt_idx is not None
|
|
1360
1383
|
stmts_to_keep_per_block[(def_.codeloc.block_addr, def_.codeloc.block_idx)].add(def_.codeloc.stmt_idx)
|
|
1361
1384
|
|
|
1362
1385
|
# find all phi variables that rely on variables that no longer exist
|
|
@@ -1369,6 +1392,7 @@ class AILSimplifier(Analysis):
|
|
|
1369
1392
|
vvarid in removed_vvar_ids for vvarid in phi_use_varids
|
|
1370
1393
|
):
|
|
1371
1394
|
loc = rd.all_vvar_definitions[rd.varid_to_vvar[phi_varid]]
|
|
1395
|
+
assert loc.block_addr is not None and loc.stmt_idx is not None
|
|
1372
1396
|
stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)].add(loc.stmt_idx)
|
|
1373
1397
|
new_removed_vvar_ids.add(phi_varid)
|
|
1374
1398
|
all_removed_var_ids.add(phi_varid)
|
|
@@ -1380,11 +1404,13 @@ class AILSimplifier(Analysis):
|
|
|
1380
1404
|
redundant_phi_and_dirty_varids = self._find_cyclic_dependent_phis_and_dirty_vvars(rd)
|
|
1381
1405
|
for varid in redundant_phi_and_dirty_varids:
|
|
1382
1406
|
loc = rd.all_vvar_definitions[rd.varid_to_vvar[varid]]
|
|
1407
|
+
assert loc.block_addr is not None and loc.stmt_idx is not None
|
|
1383
1408
|
stmts_to_remove_per_block[(loc.block_addr, loc.block_idx)].add(loc.stmt_idx)
|
|
1384
1409
|
stmts_to_keep_per_block[(loc.block_addr, loc.block_idx)].discard(loc.stmt_idx)
|
|
1385
1410
|
|
|
1386
1411
|
for codeloc in self._calls_to_remove | self._assignments_to_remove:
|
|
1387
1412
|
# this call can be removed. make sure it exists in stmts_to_remove_per_block
|
|
1413
|
+
assert codeloc.block_addr is not None and codeloc.stmt_idx is not None
|
|
1388
1414
|
stmts_to_remove_per_block[codeloc.block_addr, codeloc.block_idx].add(codeloc.stmt_idx)
|
|
1389
1415
|
|
|
1390
1416
|
simplified = False
|
|
@@ -1540,7 +1566,7 @@ class AILSimplifier(Analysis):
|
|
|
1540
1566
|
if bail:
|
|
1541
1567
|
continue
|
|
1542
1568
|
|
|
1543
|
-
if all(varid in phi_and_dirty_vvar_ids for varid in scc):
|
|
1569
|
+
if all(varid in phi_and_dirty_vvar_ids or rd.varid_to_vvar[varid].was_reg for varid in scc):
|
|
1544
1570
|
cyclic_dependent_phi_varids |= set(scc)
|
|
1545
1571
|
|
|
1546
1572
|
return cyclic_dependent_phi_varids
|
|
@@ -1554,7 +1580,7 @@ class AILSimplifier(Analysis):
|
|
|
1554
1580
|
if rewriter_cls is None:
|
|
1555
1581
|
return False
|
|
1556
1582
|
|
|
1557
|
-
walker =
|
|
1583
|
+
walker = AILBlockWalker()
|
|
1558
1584
|
|
|
1559
1585
|
class _any_update:
|
|
1560
1586
|
"""
|
|
@@ -1563,7 +1589,9 @@ class AILSimplifier(Analysis):
|
|
|
1563
1589
|
|
|
1564
1590
|
v = False
|
|
1565
1591
|
|
|
1566
|
-
def _handle_expr(
|
|
1592
|
+
def _handle_expr(
|
|
1593
|
+
expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: Block | None
|
|
1594
|
+
) -> Expression | None:
|
|
1567
1595
|
if isinstance(expr, VEXCCallExpression):
|
|
1568
1596
|
rewriter = rewriter_cls(expr, self.project.arch)
|
|
1569
1597
|
if rewriter.result is not None:
|
|
@@ -1574,8 +1602,6 @@ class AILSimplifier(Analysis):
|
|
|
1574
1602
|
return AILBlockWalker._handle_expr(walker, expr_idx, expr, stmt_idx, stmt, block)
|
|
1575
1603
|
|
|
1576
1604
|
blocks_by_addr_and_idx = {(node.addr, node.idx): node for node in self.func_graph.nodes()}
|
|
1577
|
-
|
|
1578
|
-
walker = AILBlockWalker()
|
|
1579
1605
|
walker._handle_expr = _handle_expr
|
|
1580
1606
|
|
|
1581
1607
|
updated = False
|
|
@@ -58,7 +58,6 @@ class BlockSimplifier(Analysis):
|
|
|
58
58
|
self,
|
|
59
59
|
block: Block | None,
|
|
60
60
|
func_addr: int | None = None,
|
|
61
|
-
remove_dead_memdefs=False,
|
|
62
61
|
stack_pointer_tracker=None,
|
|
63
62
|
peephole_optimizations: None | (
|
|
64
63
|
Iterable[type[PeepholeOptimizationStmtBase] | type[PeepholeOptimizationExprBase]]
|
|
@@ -74,7 +73,6 @@ class BlockSimplifier(Analysis):
|
|
|
74
73
|
self.block = block
|
|
75
74
|
self.func_addr = func_addr
|
|
76
75
|
|
|
77
|
-
self._remove_dead_memdefs = remove_dead_memdefs
|
|
78
76
|
self._stack_pointer_tracker = stack_pointer_tracker
|
|
79
77
|
|
|
80
78
|
if peephole_optimizations is None:
|
|
@@ -5,9 +5,19 @@ import logging
|
|
|
5
5
|
|
|
6
6
|
import archinfo
|
|
7
7
|
from ailment import Stmt, Expr, Const
|
|
8
|
+
from ailment.manager import Manager
|
|
8
9
|
|
|
9
10
|
from angr.procedures.stubs.format_parser import FormatParser, FormatSpecifier
|
|
10
|
-
from angr.sim_type import
|
|
11
|
+
from angr.sim_type import (
|
|
12
|
+
SimTypeBottom,
|
|
13
|
+
SimTypePointer,
|
|
14
|
+
SimTypeChar,
|
|
15
|
+
SimTypeInt,
|
|
16
|
+
SimTypeFloat,
|
|
17
|
+
dereference_simtype,
|
|
18
|
+
SimTypeFunction,
|
|
19
|
+
SimTypeLongLong,
|
|
20
|
+
)
|
|
11
21
|
from angr.calling_conventions import SimRegArg, SimStackArg, SimCC, SimStructArg, SimComboArg
|
|
12
22
|
from angr.knowledge_plugins.key_definitions.constants import OP_BEFORE
|
|
13
23
|
from angr.analyses import Analysis, register_analysis
|
|
@@ -27,7 +37,7 @@ class CallSiteMaker(Analysis):
|
|
|
27
37
|
Add calling convention, declaration, and args to a call site.
|
|
28
38
|
"""
|
|
29
39
|
|
|
30
|
-
def __init__(self, block, reaching_definitions=None, stack_pointer_tracker=None, ail_manager=None):
|
|
40
|
+
def __init__(self, block, reaching_definitions=None, stack_pointer_tracker=None, ail_manager: Manager = None):
|
|
31
41
|
self.block = block
|
|
32
42
|
|
|
33
43
|
self._reaching_definitions = reaching_definitions
|
|
@@ -60,7 +70,7 @@ class CallSiteMaker(Analysis):
|
|
|
60
70
|
return
|
|
61
71
|
|
|
62
72
|
cc = None
|
|
63
|
-
prototype = None
|
|
73
|
+
prototype: SimTypeFunction | None = None
|
|
64
74
|
func = None
|
|
65
75
|
stack_arg_locs: list[SimStackArg] = []
|
|
66
76
|
stackarg_sp_diff = 0
|
|
@@ -106,7 +116,9 @@ class CallSiteMaker(Analysis):
|
|
|
106
116
|
for typelib_name in prototype_lib.type_collection_names:
|
|
107
117
|
type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
|
|
108
118
|
if type_collections:
|
|
109
|
-
prototype = dereference_simtype(prototype, type_collections).with_arch(
|
|
119
|
+
prototype = dereference_simtype(prototype, type_collections).with_arch( # type: ignore
|
|
120
|
+
self.project.arch
|
|
121
|
+
)
|
|
110
122
|
|
|
111
123
|
args = []
|
|
112
124
|
arg_vvars = []
|
|
@@ -120,15 +132,18 @@ class CallSiteMaker(Analysis):
|
|
|
120
132
|
arg_locs = cc.arg_locs(prototype)
|
|
121
133
|
if prototype.variadic:
|
|
122
134
|
# determine the number of variadic arguments
|
|
135
|
+
assert func is not None
|
|
123
136
|
variadic_args = self._determine_variadic_arguments(func, cc, call_stmt)
|
|
124
137
|
if variadic_args:
|
|
125
138
|
callsite_ty = copy.copy(prototype)
|
|
126
|
-
|
|
139
|
+
callsite_args = list(callsite_ty.args)
|
|
140
|
+
base_type = SimTypeInt if self.project.arch.bits == 32 else SimTypeLongLong
|
|
127
141
|
for _ in range(variadic_args):
|
|
128
|
-
|
|
142
|
+
callsite_args.append(base_type().with_arch(self.project.arch))
|
|
143
|
+
callsite_ty.args = tuple(callsite_args)
|
|
129
144
|
arg_locs = cc.arg_locs(callsite_ty)
|
|
130
145
|
|
|
131
|
-
if arg_locs is not None:
|
|
146
|
+
if arg_locs is not None and cc is not None:
|
|
132
147
|
expanded_arg_locs = []
|
|
133
148
|
for arg_loc in arg_locs:
|
|
134
149
|
if isinstance(arg_loc, SimComboArg):
|
|
@@ -155,6 +170,38 @@ class CallSiteMaker(Analysis):
|
|
|
155
170
|
oident=vvar_def.oident,
|
|
156
171
|
**vvar_def.tags,
|
|
157
172
|
)
|
|
173
|
+
vvar_def_reg_offset = None
|
|
174
|
+
if vvar_def.was_reg:
|
|
175
|
+
vvar_def_reg_offset = vvar_def.reg_offset
|
|
176
|
+
elif (
|
|
177
|
+
vvar_def.was_parameter
|
|
178
|
+
and vvar_def.parameter_category == Expr.VirtualVariableCategory.REGISTER
|
|
179
|
+
):
|
|
180
|
+
vvar_def_reg_offset = vvar_def.parameter_reg_offset
|
|
181
|
+
|
|
182
|
+
if vvar_def_reg_offset is not None and offset > vvar_def_reg_offset:
|
|
183
|
+
# we need to shift the value
|
|
184
|
+
vvar_use = Expr.BinaryOp(
|
|
185
|
+
self._ail_manager.next_atom(),
|
|
186
|
+
"Shr",
|
|
187
|
+
[
|
|
188
|
+
vvar_use,
|
|
189
|
+
Expr.Const(
|
|
190
|
+
self._ail_manager.next_atom(), None, (offset - vvar_def_reg_offset) * 8, 8
|
|
191
|
+
),
|
|
192
|
+
],
|
|
193
|
+
**vvar_use.tags,
|
|
194
|
+
)
|
|
195
|
+
if vvar_def.size > arg_loc.size:
|
|
196
|
+
# we need to narrow the value
|
|
197
|
+
vvar_use = Expr.Convert(
|
|
198
|
+
self._ail_manager.next_atom(),
|
|
199
|
+
vvar_use.bits,
|
|
200
|
+
arg_loc.size * self.project.arch.byte_width,
|
|
201
|
+
False,
|
|
202
|
+
vvar_use,
|
|
203
|
+
**vvar_use.tags,
|
|
204
|
+
)
|
|
158
205
|
args.append(vvar_use)
|
|
159
206
|
else:
|
|
160
207
|
reg = Expr.Register(
|
|
@@ -219,6 +266,7 @@ class CallSiteMaker(Analysis):
|
|
|
219
266
|
# calculate stack offsets for arguments that are put on the stack. these offsets will be consumed by
|
|
220
267
|
# simplification steps in the future, which may decide to remove statements that store arguments on the stack.
|
|
221
268
|
if stack_arg_locs:
|
|
269
|
+
assert self._stack_pointer_tracker is not None
|
|
222
270
|
sp_offset = self._stack_pointer_tracker.offset_before(call_stmt.ins_addr, self.project.arch.sp_offset)
|
|
223
271
|
if sp_offset is None:
|
|
224
272
|
l.warning(
|
|
@@ -233,8 +281,22 @@ class CallSiteMaker(Analysis):
|
|
|
233
281
|
}
|
|
234
282
|
|
|
235
283
|
ret_expr = call_stmt.ret_expr
|
|
236
|
-
|
|
237
|
-
#
|
|
284
|
+
fp_ret_expr = call_stmt.fp_ret_expr
|
|
285
|
+
# if ret_expr and fp_ret_expr are None, it means in previous steps (such as during AIL simplification) we have
|
|
286
|
+
# deemed the return value of this call statement as useless and is removed.
|
|
287
|
+
|
|
288
|
+
if (
|
|
289
|
+
ret_expr is not None
|
|
290
|
+
and fp_ret_expr is not None
|
|
291
|
+
and prototype is not None
|
|
292
|
+
and prototype.returnty is not None
|
|
293
|
+
):
|
|
294
|
+
# we need to determine the return type of this call (ret_expr vs fp_ret_expr)
|
|
295
|
+
is_float = isinstance(prototype.returnty, SimTypeFloat)
|
|
296
|
+
if is_float:
|
|
297
|
+
ret_expr = None
|
|
298
|
+
else:
|
|
299
|
+
fp_ret_expr = None
|
|
238
300
|
|
|
239
301
|
if (
|
|
240
302
|
ret_expr is not None
|
|
@@ -243,9 +305,9 @@ class CallSiteMaker(Analysis):
|
|
|
243
305
|
and not isinstance(prototype.returnty, SimTypeBottom)
|
|
244
306
|
and not isinstance(ret_expr, Expr.VirtualVariable)
|
|
245
307
|
):
|
|
246
|
-
# try to narrow the return expression if needed
|
|
308
|
+
# try to narrow the non-float return expression if needed
|
|
247
309
|
ret_type_bits = prototype.returnty.with_arch(self.project.arch).size
|
|
248
|
-
if ret_expr.bits > ret_type_bits:
|
|
310
|
+
if ret_type_bits is not None and ret_expr.bits > ret_type_bits:
|
|
249
311
|
ret_expr = ret_expr.copy()
|
|
250
312
|
ret_expr.bits = ret_type_bits
|
|
251
313
|
# TODO: Support narrowing virtual variables
|
|
@@ -257,6 +319,7 @@ class CallSiteMaker(Analysis):
|
|
|
257
319
|
prototype=prototype,
|
|
258
320
|
args=args,
|
|
259
321
|
ret_expr=ret_expr,
|
|
322
|
+
fp_ret_expr=fp_ret_expr,
|
|
260
323
|
arg_vvars=arg_vvars,
|
|
261
324
|
**call_stmt.tags,
|
|
262
325
|
)
|
|
@@ -291,7 +354,7 @@ class CallSiteMaker(Analysis):
|
|
|
291
354
|
l.warning("TODO: Unsupported statement type %s for definitions.", type(stmt))
|
|
292
355
|
return None
|
|
293
356
|
|
|
294
|
-
def _resolve_register_argument(self, arg_loc) -> tuple[
|
|
357
|
+
def _resolve_register_argument(self, arg_loc) -> tuple[Expr.Expression | None, Expr.VirtualVariable] | None:
|
|
295
358
|
offset = arg_loc.check_offset(self.project.arch)
|
|
296
359
|
|
|
297
360
|
if self._reaching_definitions is not None:
|
|
@@ -310,6 +373,8 @@ class CallSiteMaker(Analysis):
|
|
|
310
373
|
return None
|
|
311
374
|
|
|
312
375
|
def _resolve_stack_argument(self, call_stmt, arg_loc) -> tuple[Any, Any]: # pylint:disable=unused-argument
|
|
376
|
+
assert self._stack_pointer_tracker is not None
|
|
377
|
+
|
|
313
378
|
size = arg_loc.size
|
|
314
379
|
offset = arg_loc.stack_offset
|
|
315
380
|
if self.project.arch.call_pushes_ret:
|
|
@@ -331,6 +396,7 @@ class CallSiteMaker(Analysis):
|
|
|
331
396
|
sp_offset, size, self.block.addr, self.block.idx, len(self.block.statements) - 1, OP_BEFORE
|
|
332
397
|
)
|
|
333
398
|
if vvar is not None:
|
|
399
|
+
# FIXME: vvar may be larger than that we ask; we may need to chop the correct value of vvar
|
|
334
400
|
value = view.get_vvar_value(vvar)
|
|
335
401
|
if value is not None and not isinstance(value, Expr.Phi):
|
|
336
402
|
return None, value
|
|
@@ -391,8 +457,8 @@ class CallSiteMaker(Analysis):
|
|
|
391
457
|
|
|
392
458
|
return s
|
|
393
459
|
|
|
394
|
-
def _determine_variadic_arguments(self, func: Function
|
|
395
|
-
if
|
|
460
|
+
def _determine_variadic_arguments(self, func: Function, cc: SimCC, call_stmt) -> int | None:
|
|
461
|
+
if "printf" in func.name or "scanf" in func.name:
|
|
396
462
|
return self._determine_variadic_arguments_for_format_strings(func, cc, call_stmt)
|
|
397
463
|
return None
|
|
398
464
|
|