angr 9.2.136__py3-none-macosx_11_0_arm64.whl → 9.2.137__py3-none-macosx_11_0_arm64.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 +2 -1
- angr/analyses/calling_convention/fact_collector.py +10 -2
- angr/analyses/cfg/cfg_base.py +3 -33
- angr/analyses/cfg/cfg_emulated.py +0 -103
- angr/analyses/cfg/cfg_fast.py +28 -12
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +15 -0
- angr/analyses/class_identifier.py +1 -2
- angr/analyses/complete_calling_conventions.py +3 -0
- angr/analyses/decompiler/ail_simplifier.py +12 -1
- 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 +77 -65
- 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/return_duplicator_base.py +1 -2
- 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 +117 -14
- angr/analyses/decompiler/utils.py +113 -8
- angr/analyses/reaching_definitions/function_handler.py +1 -1
- angr/analyses/s_liveness.py +5 -1
- angr/analyses/s_propagator.py +25 -4
- 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/stack_pointer_tracker.py +26 -16
- 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 +22 -1
- angr/block.py +59 -20
- angr/engines/pcode/emulate.py +1 -1
- angr/engines/pcode/lifter.py +31 -18
- angr/engines/soot/expressions/__init__.py +2 -4
- angr/engines/soot/statements/__init__.py +1 -2
- angr/engines/soot/values/__init__.py +1 -2
- angr/engines/successors.py +11 -6
- angr/engines/vex/lifter.py +9 -6
- angr/flirt/build_sig.py +8 -15
- angr/knowledge_plugins/functions/function.py +0 -6
- angr/knowledge_plugins/functions/soot_function.py +5 -8
- angr/knowledge_plugins/variables/variable_manager.py +16 -10
- angr/lib/angr_native.dylib +0 -0
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/METADATA +7 -7
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/RECORD +60 -59
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/WHEEL +1 -1
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/LICENSE +0 -0
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/entry_points.txt +0 -0
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/top_level.txt +0 -0
|
@@ -49,7 +49,6 @@ from .optimization_passes import (
|
|
|
49
49
|
DUPLICATING_OPTS,
|
|
50
50
|
CONDENSING_OPTS,
|
|
51
51
|
)
|
|
52
|
-
from .utils import first_nonlabel_statement_id
|
|
53
52
|
|
|
54
53
|
if TYPE_CHECKING:
|
|
55
54
|
from angr.knowledge_plugins.cfg import CFGModel
|
|
@@ -461,12 +460,12 @@ class Clinic(Analysis):
|
|
|
461
460
|
# Make function arguments
|
|
462
461
|
self._update_progress(33.0, text="Making argument list")
|
|
463
462
|
arg_list = self._make_argument_list()
|
|
464
|
-
arg_vvars =
|
|
465
|
-
|
|
463
|
+
arg_vvars = self._create_function_argument_vvars(arg_list)
|
|
464
|
+
func_args = {arg_vvar for arg_vvar, _ in arg_vvars.values()}
|
|
466
465
|
|
|
467
466
|
# Transform the graph into partial SSA form
|
|
468
467
|
self._update_progress(35.0, text="Transforming to partial-SSA form")
|
|
469
|
-
ail_graph = self._transform_to_ssa_level0(ail_graph)
|
|
468
|
+
ail_graph = self._transform_to_ssa_level0(ail_graph, func_args)
|
|
470
469
|
|
|
471
470
|
# full-function constant-only propagation
|
|
472
471
|
self._update_progress(36.0, text="Constant propagation")
|
|
@@ -521,7 +520,7 @@ class Clinic(Analysis):
|
|
|
521
520
|
)
|
|
522
521
|
|
|
523
522
|
# rewrite (qualified) stack variables into SSA form
|
|
524
|
-
ail_graph = self._transform_to_ssa_level1(ail_graph)
|
|
523
|
+
ail_graph = self._transform_to_ssa_level1(ail_graph, func_args)
|
|
525
524
|
|
|
526
525
|
# clear _blocks_by_addr_and_size so no one can use it again
|
|
527
526
|
# TODO: Totally remove this dict
|
|
@@ -529,10 +528,12 @@ class Clinic(Analysis):
|
|
|
529
528
|
|
|
530
529
|
# Rust-specific; only call this on Rust binaries when we can identify language and compiler
|
|
531
530
|
ail_graph = self._rewrite_rust_probestack_call(ail_graph)
|
|
531
|
+
# Windows-specific
|
|
532
|
+
ail_graph = self._rewrite_windows_stkchk_call(ail_graph)
|
|
532
533
|
|
|
533
534
|
# Make call-sites
|
|
534
535
|
self._update_progress(50.0, text="Making callsites")
|
|
535
|
-
_, stackarg_offsets, removed_vvar_ids = self._make_callsites(ail_graph, stack_pointer_tracker=spt)
|
|
536
|
+
_, stackarg_offsets, removed_vvar_ids = self._make_callsites(ail_graph, func_args, stack_pointer_tracker=spt)
|
|
536
537
|
|
|
537
538
|
# Run simplification passes
|
|
538
539
|
self._update_progress(53.0, text="Running simplifications 2")
|
|
@@ -1306,84 +1307,57 @@ class Clinic(Analysis):
|
|
|
1306
1307
|
return ail_graph
|
|
1307
1308
|
|
|
1308
1309
|
@timethis
|
|
1309
|
-
def
|
|
1310
|
-
|
|
1311
|
-
arg_list: list[SimVariable],
|
|
1312
|
-
ail_graph: networkx.DiGraph,
|
|
1313
|
-
arg_vvars: dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]],
|
|
1314
|
-
) -> networkx.DiGraph:
|
|
1315
|
-
entrypoint = next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr))
|
|
1316
|
-
new_stmts = []
|
|
1310
|
+
def _create_function_argument_vvars(self, arg_list) -> dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]]:
|
|
1311
|
+
arg_vvars = {}
|
|
1317
1312
|
for arg in arg_list:
|
|
1318
|
-
if
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
# get the full register if needed
|
|
1322
|
-
basereg_offset, basereg_size = self.project.arch.get_base_register(arg.reg, size=arg.size)
|
|
1323
|
-
|
|
1324
|
-
arg_vvar = ailment.Expr.VirtualVariable(
|
|
1325
|
-
self._ail_manager.next_atom(),
|
|
1326
|
-
self.vvar_id_start,
|
|
1327
|
-
arg.bits,
|
|
1328
|
-
ailment.Expr.VirtualVariableCategory.PARAMETER,
|
|
1329
|
-
oident=arg.reg,
|
|
1330
|
-
ins_addr=self.function.addr,
|
|
1331
|
-
vex_block_addr=self.function.addr,
|
|
1332
|
-
)
|
|
1333
|
-
self.vvar_id_start += 1
|
|
1334
|
-
arg_vvars[arg_vvar.varid] = arg_vvar, arg
|
|
1335
|
-
|
|
1336
|
-
if basereg_size != arg.size:
|
|
1337
|
-
# extend the value to the full register
|
|
1338
|
-
arg_vvar = ailment.Expr.Convert(
|
|
1313
|
+
if isinstance(arg, SimRegisterVariable):
|
|
1314
|
+
# get the full register if needed
|
|
1315
|
+
arg_vvar = ailment.Expr.VirtualVariable(
|
|
1339
1316
|
self._ail_manager.next_atom(),
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1317
|
+
self.vvar_id_start,
|
|
1318
|
+
arg.bits,
|
|
1319
|
+
ailment.Expr.VirtualVariableCategory.PARAMETER,
|
|
1320
|
+
oident=(ailment.Expr.VirtualVariableCategory.REGISTER, arg.reg),
|
|
1344
1321
|
ins_addr=self.function.addr,
|
|
1345
1322
|
vex_block_addr=self.function.addr,
|
|
1346
1323
|
)
|
|
1324
|
+
self.vvar_id_start += 1
|
|
1325
|
+
arg_vvars[arg_vvar.varid] = arg_vvar, arg
|
|
1326
|
+
elif isinstance(arg, SimStackVariable):
|
|
1327
|
+
arg_vvar = ailment.Expr.VirtualVariable(
|
|
1328
|
+
self._ail_manager.next_atom(),
|
|
1329
|
+
self.vvar_id_start,
|
|
1330
|
+
arg.bits,
|
|
1331
|
+
ailment.Expr.VirtualVariableCategory.PARAMETER,
|
|
1332
|
+
oident=(ailment.Expr.VirtualVariableCategory.STACK, arg.offset),
|
|
1333
|
+
ins_addr=self.function.addr,
|
|
1334
|
+
vex_block_addr=self.function.addr,
|
|
1335
|
+
)
|
|
1336
|
+
self.vvar_id_start += 1
|
|
1337
|
+
arg_vvars[arg_vvar.varid] = arg_vvar, arg
|
|
1347
1338
|
|
|
1348
|
-
|
|
1349
|
-
self._ail_manager.next_atom(),
|
|
1350
|
-
None,
|
|
1351
|
-
basereg_offset,
|
|
1352
|
-
basereg_size * self.project.arch.byte_width,
|
|
1353
|
-
ins_addr=self.function.addr,
|
|
1354
|
-
vex_block_addr=self.function.addr,
|
|
1355
|
-
)
|
|
1356
|
-
stmt = ailment.Stmt.Assignment(
|
|
1357
|
-
self._ail_manager.next_atom(),
|
|
1358
|
-
fullreg_dst,
|
|
1359
|
-
arg_vvar,
|
|
1360
|
-
ins_addr=self.function.addr,
|
|
1361
|
-
vex_block_addr=self.function.addr,
|
|
1362
|
-
)
|
|
1363
|
-
new_stmts.append(stmt)
|
|
1364
|
-
|
|
1365
|
-
non_label_stmt_idx = first_nonlabel_statement_id(entrypoint)
|
|
1366
|
-
# update the ail block in-place
|
|
1367
|
-
entrypoint.statements = (
|
|
1368
|
-
entrypoint.statements[:non_label_stmt_idx] + new_stmts + entrypoint.statements[non_label_stmt_idx:]
|
|
1369
|
-
)
|
|
1370
|
-
return ail_graph
|
|
1339
|
+
return arg_vvars
|
|
1371
1340
|
|
|
1372
1341
|
@timethis
|
|
1373
|
-
def _transform_to_ssa_level0(
|
|
1342
|
+
def _transform_to_ssa_level0(
|
|
1343
|
+
self, ail_graph: networkx.DiGraph, func_args: set[ailment.Expr.VirtualVariable]
|
|
1344
|
+
) -> networkx.DiGraph:
|
|
1374
1345
|
ssailification = self.project.analyses[Ssailification].prep(fail_fast=self._fail_fast)(
|
|
1375
1346
|
self.function,
|
|
1376
1347
|
ail_graph,
|
|
1377
1348
|
entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
|
|
1378
1349
|
ail_manager=self._ail_manager,
|
|
1379
1350
|
ssa_stackvars=False,
|
|
1351
|
+
func_args=func_args,
|
|
1380
1352
|
vvar_id_start=self.vvar_id_start,
|
|
1381
1353
|
)
|
|
1382
1354
|
self.vvar_id_start = ssailification.max_vvar_id + 1
|
|
1383
1355
|
return ssailification.out_graph
|
|
1384
1356
|
|
|
1385
1357
|
@timethis
|
|
1386
|
-
def _transform_to_ssa_level1(
|
|
1358
|
+
def _transform_to_ssa_level1(
|
|
1359
|
+
self, ail_graph: networkx.DiGraph, func_args: set[ailment.Expr.VirtualVariable]
|
|
1360
|
+
) -> networkx.DiGraph:
|
|
1387
1361
|
ssailification = self.project.analyses.Ssailification(
|
|
1388
1362
|
self.function,
|
|
1389
1363
|
ail_graph,
|
|
@@ -1392,6 +1366,7 @@ class Clinic(Analysis):
|
|
|
1392
1366
|
ail_manager=self._ail_manager,
|
|
1393
1367
|
ssa_tmps=True,
|
|
1394
1368
|
ssa_stackvars=True,
|
|
1369
|
+
func_args=func_args,
|
|
1395
1370
|
vvar_id_start=self.vvar_id_start,
|
|
1396
1371
|
)
|
|
1397
1372
|
self.vvar_id_start = ssailification.max_vvar_id + 1
|
|
@@ -1449,7 +1424,7 @@ class Clinic(Analysis):
|
|
|
1449
1424
|
return []
|
|
1450
1425
|
|
|
1451
1426
|
@timethis
|
|
1452
|
-
def _make_callsites(self, ail_graph, stack_pointer_tracker=None):
|
|
1427
|
+
def _make_callsites(self, ail_graph, func_args: set[ailment.Expr.VirtualVariable], stack_pointer_tracker=None):
|
|
1453
1428
|
"""
|
|
1454
1429
|
Simplify all function call statements.
|
|
1455
1430
|
"""
|
|
@@ -1458,6 +1433,7 @@ class Clinic(Analysis):
|
|
|
1458
1433
|
rd = self.project.analyses.SReachingDefinitions(
|
|
1459
1434
|
subject=self.function,
|
|
1460
1435
|
func_graph=ail_graph,
|
|
1436
|
+
func_args=func_args,
|
|
1461
1437
|
fail_fast=self._fail_fast,
|
|
1462
1438
|
# use_callee_saved_regs_at_return=not self._register_save_areas_removed, FIXME
|
|
1463
1439
|
)
|
|
@@ -1714,6 +1690,9 @@ class Clinic(Analysis):
|
|
|
1714
1690
|
elif stmt_type is ailment.Stmt.ConditionalJump:
|
|
1715
1691
|
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.condition)
|
|
1716
1692
|
|
|
1693
|
+
elif stmt_type is ailment.Stmt.Jump and not isinstance(stmt.target, ailment.Expr.Const):
|
|
1694
|
+
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.target)
|
|
1695
|
+
|
|
1717
1696
|
elif stmt_type is ailment.Stmt.Call:
|
|
1718
1697
|
self._link_variables_on_call(variable_manager, global_variables, block, stmt_idx, stmt, is_expr=False)
|
|
1719
1698
|
|
|
@@ -2767,6 +2746,39 @@ class Clinic(Analysis):
|
|
|
2767
2746
|
break
|
|
2768
2747
|
return ail_graph
|
|
2769
2748
|
|
|
2749
|
+
def _rewrite_windows_stkchk_call(self, ail_graph) -> networkx.DiGraph:
|
|
2750
|
+
if not (self.project.simos is not None and self.project.simos.name == "Win32"):
|
|
2751
|
+
return ail_graph
|
|
2752
|
+
|
|
2753
|
+
for node in ail_graph:
|
|
2754
|
+
if not node.statements or ail_graph.out_degree[node] != 1:
|
|
2755
|
+
continue
|
|
2756
|
+
last_stmt = node.statements[-1]
|
|
2757
|
+
if isinstance(last_stmt, ailment.Stmt.Call) and isinstance(last_stmt.target, ailment.Expr.Const):
|
|
2758
|
+
func = (
|
|
2759
|
+
self.project.kb.functions.get_by_addr(last_stmt.target.value)
|
|
2760
|
+
if self.project.kb.functions.contains_addr(last_stmt.target.value)
|
|
2761
|
+
else None
|
|
2762
|
+
)
|
|
2763
|
+
if func is not None and func.name == "__chkstk":
|
|
2764
|
+
# get rid of this call
|
|
2765
|
+
node.statements = node.statements[:-1]
|
|
2766
|
+
if self.project.arch.call_pushes_ret and node.statements:
|
|
2767
|
+
last_stmt = node.statements[-1]
|
|
2768
|
+
succ = next(iter(ail_graph.successors(node)))
|
|
2769
|
+
if (
|
|
2770
|
+
isinstance(last_stmt, ailment.Stmt.Store)
|
|
2771
|
+
and isinstance(last_stmt.addr, ailment.Expr.StackBaseOffset)
|
|
2772
|
+
and isinstance(last_stmt.addr.offset, int)
|
|
2773
|
+
and last_stmt.addr.offset < 0
|
|
2774
|
+
and isinstance(last_stmt.data, ailment.Expr.Const)
|
|
2775
|
+
and last_stmt.data.value == succ.addr
|
|
2776
|
+
):
|
|
2777
|
+
# remove the statement that pushes the return address
|
|
2778
|
+
node.statements = node.statements[:-1]
|
|
2779
|
+
break
|
|
2780
|
+
return ail_graph
|
|
2781
|
+
|
|
2770
2782
|
def _rewrite_alloca(self, ail_graph):
|
|
2771
2783
|
# pylint:disable=too-many-boolean-expressions
|
|
2772
2784
|
alloca_node = None
|
|
@@ -368,6 +368,7 @@ class Decompiler(Analysis):
|
|
|
368
368
|
self.cache.clinic = self.clinic
|
|
369
369
|
|
|
370
370
|
self.kb.decompilations[(self.func.addr, self._flavor)] = self.cache
|
|
371
|
+
self._finish_progress()
|
|
371
372
|
|
|
372
373
|
def _recover_regions(self, graph: networkx.DiGraph, condition_processor, update_graph: bool = True):
|
|
373
374
|
return self.project.analyses[RegionIdentifier].prep(kb=self.kb, fail_fast=self._fail_fast)(
|
|
@@ -77,6 +77,8 @@ class DephicationBase(Analysis):
|
|
|
77
77
|
mapped_phivarid = phivarid_to_phivarid.get(phi_varid, phi_varid)
|
|
78
78
|
for varid in varids:
|
|
79
79
|
vvar_to_vvar[varid] = mapped_phivarid
|
|
80
|
+
if phi_varid != mapped_phivarid:
|
|
81
|
+
vvar_to_vvar[phi_varid] = mapped_phivarid
|
|
80
82
|
|
|
81
83
|
return vvar_to_vvar
|
|
82
84
|
|
|
@@ -88,12 +88,14 @@ class SimEngineDephiRewriting(SimEngineNostmtAIL[None, Expression | None, Statem
|
|
|
88
88
|
)
|
|
89
89
|
|
|
90
90
|
if new_dst is not None or new_src is not None:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
91
|
+
# ensure we do not generate vvar_A = vvar_A
|
|
92
|
+
dst = stmt.dst if new_dst is None else new_dst
|
|
93
|
+
src = stmt.src if new_src is None else new_src
|
|
94
|
+
if isinstance(dst, VirtualVariable) and isinstance(src, VirtualVariable) and dst.varid == src.varid:
|
|
95
|
+
# skip it
|
|
96
|
+
return ()
|
|
97
|
+
|
|
98
|
+
return Assignment(stmt.idx, dst, src, **stmt.tags)
|
|
97
99
|
return None
|
|
98
100
|
|
|
99
101
|
def _handle_stmt_Store(self, stmt):
|
|
@@ -5,7 +5,7 @@ from typing import Any
|
|
|
5
5
|
|
|
6
6
|
from ailment.block import Block
|
|
7
7
|
from ailment.statement import Assignment
|
|
8
|
-
from ailment.expression import VirtualVariable, Phi
|
|
8
|
+
from ailment.expression import VirtualVariable, Phi, BinaryOp, UnaryOp
|
|
9
9
|
|
|
10
10
|
import angr
|
|
11
11
|
from angr.utils.ail import is_phi_assignment
|
|
@@ -60,6 +60,9 @@ class SeqNodeRewriter(SequenceWalker):
|
|
|
60
60
|
Block: self._handle_Block,
|
|
61
61
|
# statement handlers
|
|
62
62
|
Assignment: self._handle_Assignment,
|
|
63
|
+
# expression handlers
|
|
64
|
+
BinaryOp: self._handle_BinaryOp,
|
|
65
|
+
UnaryOp: self._handle_UnaryOp,
|
|
63
66
|
}
|
|
64
67
|
)
|
|
65
68
|
|
|
@@ -74,6 +77,12 @@ class SeqNodeRewriter(SequenceWalker):
|
|
|
74
77
|
def _handle_Assignment(self, stmt: Assignment, **kwargs) -> Assignment: # pylint:disable=unused-argument
|
|
75
78
|
return self.engine._handle_stmt_Assignment(stmt)
|
|
76
79
|
|
|
80
|
+
def _handle_BinaryOp(self, expr, **kwargs): # pylint:disable=unused-argument
|
|
81
|
+
return self.engine._handle_expr_BinaryOp(expr)
|
|
82
|
+
|
|
83
|
+
def _handle_UnaryOp(self, expr, **kwargs): # pylint:disable=unused-argument
|
|
84
|
+
return self.engine._handle_expr_UnaryOp(expr)
|
|
85
|
+
|
|
77
86
|
def _handle_Block(self, block: Block, **kwargs) -> Block | None: # pylint:disable=unused-argument
|
|
78
87
|
self.engine.out_block = None
|
|
79
88
|
self.engine.process(None, block=block)
|
|
@@ -571,8 +571,7 @@ class ReturnDuplicatorBase:
|
|
|
571
571
|
new_name = stmt.name if stmt.name else f"Label_{stmt.ins_addr:x}"
|
|
572
572
|
if stmt.block_idx is not None:
|
|
573
573
|
suffix = f"__{stmt.block_idx}"
|
|
574
|
-
|
|
575
|
-
new_name = new_name[: -len(suffix)]
|
|
574
|
+
new_name = new_name.removesuffix(suffix)
|
|
576
575
|
else:
|
|
577
576
|
new_name = stmt.name
|
|
578
577
|
new_name += f"__{block.idx}"
|
|
@@ -204,13 +204,17 @@ class SequenceWalker:
|
|
|
204
204
|
|
|
205
205
|
new_false_node = self._handle(node.false_node, parent=node, index=1) if node.false_node is not None else None
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
new_condition = (
|
|
208
|
+
self._handle(node.condition, parent=node, label="condition") if node.condition is not None else None
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
if new_true_node is None and new_false_node is None and new_condition is None:
|
|
208
212
|
return None
|
|
209
213
|
|
|
210
214
|
return ConditionNode(
|
|
211
215
|
node.addr,
|
|
212
216
|
node.reaching_condition,
|
|
213
|
-
node.condition,
|
|
217
|
+
node.condition if new_condition is None else new_condition,
|
|
214
218
|
node.true_node if new_true_node is None else new_true_node,
|
|
215
219
|
false_node=node.false_node if new_false_node is None else new_false_node,
|
|
216
220
|
)
|
|
@@ -40,6 +40,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
40
40
|
stackvar_locs: dict[int, int],
|
|
41
41
|
rewrite_tmps: bool,
|
|
42
42
|
ail_manager,
|
|
43
|
+
func_args: set[VirtualVariable],
|
|
43
44
|
vvar_id_start: int = 0,
|
|
44
45
|
):
|
|
45
46
|
self.project = project
|
|
@@ -55,6 +56,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
55
56
|
self._stackvar_locs = stackvar_locs
|
|
56
57
|
self._rewrite_tmps = rewrite_tmps
|
|
57
58
|
self._ail_manager = ail_manager
|
|
59
|
+
self._func_args = func_args
|
|
58
60
|
self._engine_ail = SimEngineSSARewriting(
|
|
59
61
|
self.project,
|
|
60
62
|
sp_tracker=sp_tracker,
|
|
@@ -205,12 +207,20 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
205
207
|
self.insert_phi_statements(node, phi_stmts)
|
|
206
208
|
|
|
207
209
|
def _initial_abstract_state(self, node) -> RewritingState:
|
|
208
|
-
|
|
210
|
+
state = RewritingState(
|
|
209
211
|
CodeLocation(node.addr, stmt_idx=0, ins_addr=node.addr, block_idx=node.idx),
|
|
210
212
|
self.project.arch,
|
|
211
213
|
self._function,
|
|
212
214
|
node,
|
|
213
215
|
)
|
|
216
|
+
# update state with function arguments
|
|
217
|
+
for func_arg in self._func_args:
|
|
218
|
+
if func_arg.oident[0] == VirtualVariableCategory.REGISTER:
|
|
219
|
+
reg_offset, reg_size = func_arg.oident[1], func_arg.size
|
|
220
|
+
state.registers[reg_offset][reg_size] = func_arg
|
|
221
|
+
elif func_arg.oident[0] == VirtualVariableCategory.STACK:
|
|
222
|
+
state.stackvars[func_arg.oident[1]][func_arg.size] = func_arg
|
|
223
|
+
return state
|
|
214
224
|
|
|
215
225
|
def _run_on_node(self, node, state: RewritingState):
|
|
216
226
|
"""
|
|
@@ -462,7 +462,7 @@ class SimEngineSSARewriting(
|
|
|
462
462
|
base_mask = Const(self.ail_manager.next_atom(), None, base_mask, existing_vvar.bits)
|
|
463
463
|
new_base_expr = BinaryOp(
|
|
464
464
|
self.ail_manager.next_atom(),
|
|
465
|
-
"
|
|
465
|
+
"And",
|
|
466
466
|
[existing_vvar, base_mask],
|
|
467
467
|
False,
|
|
468
468
|
bits=existing_vvar.bits,
|
|
@@ -618,6 +618,15 @@ class SimEngineSSARewriting(
|
|
|
618
618
|
):
|
|
619
619
|
vvar = self.state.registers[reg_expr.reg_offset][reg_expr.size]
|
|
620
620
|
assert vvar is not None
|
|
621
|
+
if vvar.category == VirtualVariableCategory.PARAMETER:
|
|
622
|
+
return VirtualVariable(
|
|
623
|
+
reg_expr.idx,
|
|
624
|
+
vvar.varid,
|
|
625
|
+
vvar.bits,
|
|
626
|
+
VirtualVariableCategory.PARAMETER,
|
|
627
|
+
oident=vvar.oident,
|
|
628
|
+
**vvar.tags,
|
|
629
|
+
)
|
|
621
630
|
return VirtualVariable(
|
|
622
631
|
reg_expr.idx,
|
|
623
632
|
vvar.varid,
|
|
@@ -640,6 +649,20 @@ class SimEngineSSARewriting(
|
|
|
640
649
|
vvar,
|
|
641
650
|
**reg_expr.tags,
|
|
642
651
|
)
|
|
652
|
+
elif reg_expr.size > existing_size:
|
|
653
|
+
# part of the variable exists... maybe it's a parameter?
|
|
654
|
+
vvar = self.state.registers[reg_expr.reg_offset][existing_size]
|
|
655
|
+
if vvar.category == VirtualVariableCategory.PARAMETER:
|
|
656
|
+
# just zero-extend it
|
|
657
|
+
return Convert(
|
|
658
|
+
self.ail_manager.next_atom(),
|
|
659
|
+
existing_size * self.project.arch.byte_width,
|
|
660
|
+
reg_expr.size * self.project.arch.byte_width,
|
|
661
|
+
False,
|
|
662
|
+
vvar,
|
|
663
|
+
**vvar.tags,
|
|
664
|
+
)
|
|
665
|
+
break
|
|
643
666
|
else:
|
|
644
667
|
break
|
|
645
668
|
|
|
@@ -651,24 +674,29 @@ class SimEngineSSARewriting(
|
|
|
651
674
|
ins_addr=reg_expr.ins_addr,
|
|
652
675
|
)
|
|
653
676
|
# extract
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
677
|
+
if reg_expr.reg_offset == vvar.oident:
|
|
678
|
+
shifted = vvar
|
|
679
|
+
else:
|
|
680
|
+
shift_amount = Const(
|
|
681
|
+
self.ail_manager.next_atom(),
|
|
682
|
+
None,
|
|
683
|
+
(reg_expr.reg_offset - vvar.oident) * self.arch.byte_width,
|
|
684
|
+
8,
|
|
685
|
+
**reg_expr.tags,
|
|
686
|
+
)
|
|
687
|
+
shifted = BinaryOp(
|
|
688
|
+
self.ail_manager.next_atom(),
|
|
689
|
+
"Shr",
|
|
690
|
+
[
|
|
691
|
+
vvar,
|
|
692
|
+
shift_amount,
|
|
693
|
+
],
|
|
694
|
+
False,
|
|
695
|
+
bits=vvar.bits,
|
|
696
|
+
**reg_expr.tags,
|
|
697
|
+
)
|
|
698
|
+
if shifted.bits == reg_expr.bits:
|
|
699
|
+
return shifted
|
|
672
700
|
return Convert(
|
|
673
701
|
self.ail_manager.next_atom(),
|
|
674
702
|
shifted.bits,
|
|
@@ -700,6 +728,15 @@ class SimEngineSSARewriting(
|
|
|
700
728
|
# TODO: Support truncation
|
|
701
729
|
# TODO: Maybe also support concatenation
|
|
702
730
|
vvar = self.state.stackvars[expr.addr.offset][expr.size]
|
|
731
|
+
if vvar.category == VirtualVariableCategory.PARAMETER:
|
|
732
|
+
return VirtualVariable(
|
|
733
|
+
expr.idx,
|
|
734
|
+
vvar.varid,
|
|
735
|
+
vvar.bits,
|
|
736
|
+
VirtualVariableCategory.PARAMETER,
|
|
737
|
+
oident=vvar.oident,
|
|
738
|
+
**vvar.tags,
|
|
739
|
+
)
|
|
703
740
|
return VirtualVariable(
|
|
704
741
|
expr.idx,
|
|
705
742
|
vvar.varid,
|
|
@@ -5,7 +5,7 @@ from collections import defaultdict
|
|
|
5
5
|
from itertools import count
|
|
6
6
|
from bisect import bisect_left
|
|
7
7
|
|
|
8
|
-
from ailment.expression import Expression, Register, StackBaseOffset, Tmp
|
|
8
|
+
from ailment.expression import Expression, Register, StackBaseOffset, Tmp, VirtualVariable, VirtualVariableCategory
|
|
9
9
|
from ailment.statement import Statement, Store
|
|
10
10
|
|
|
11
11
|
from angr.knowledge_plugins.functions import Function
|
|
@@ -34,6 +34,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
34
34
|
ail_manager=None,
|
|
35
35
|
ssa_stackvars: bool = False,
|
|
36
36
|
ssa_tmps: bool = False,
|
|
37
|
+
func_args: set[VirtualVariable] | None = None,
|
|
37
38
|
vvar_id_start: int = 0,
|
|
38
39
|
):
|
|
39
40
|
"""
|
|
@@ -53,6 +54,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
53
54
|
self._ail_manager = ail_manager
|
|
54
55
|
self._ssa_stackvars = ssa_stackvars
|
|
55
56
|
self._ssa_tmps = ssa_tmps
|
|
57
|
+
self._func_args = func_args if func_args is not None else set()
|
|
56
58
|
self._entry = (
|
|
57
59
|
entry
|
|
58
60
|
if entry is not None
|
|
@@ -71,6 +73,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
71
73
|
bp_as_gpr,
|
|
72
74
|
ssa_stackvars,
|
|
73
75
|
ssa_tmps,
|
|
76
|
+
self._func_args,
|
|
74
77
|
)
|
|
75
78
|
|
|
76
79
|
# calculate virtual variables and phi nodes
|
|
@@ -91,6 +94,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
91
94
|
self._stackvar_locs,
|
|
92
95
|
self._ssa_tmps,
|
|
93
96
|
self._ail_manager,
|
|
97
|
+
self._func_args,
|
|
94
98
|
vvar_id_start=vvar_id_start,
|
|
95
99
|
)
|
|
96
100
|
self.out_graph = rewriter.out_graph
|
|
@@ -122,6 +126,11 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
122
126
|
# for stack variables, we collect all definitions and identify stack variable locations using heuristics
|
|
123
127
|
|
|
124
128
|
stackvar_locs = self._synthesize_stackvar_locs([def_ for def_, _ in def_to_loc if isinstance(def_, Store)])
|
|
129
|
+
# handle function arguments
|
|
130
|
+
if self._func_args:
|
|
131
|
+
for func_arg in self._func_args:
|
|
132
|
+
if func_arg.oident[0] == VirtualVariableCategory.STACK:
|
|
133
|
+
stackvar_locs[func_arg.oident[1]] = func_arg.size
|
|
125
134
|
sorted_stackvar_offs = sorted(stackvar_locs)
|
|
126
135
|
else:
|
|
127
136
|
stackvar_locs = {}
|
|
@@ -137,9 +146,10 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
137
146
|
udef_to_defs[("reg", base_off, base_reg_bits)].add(def_)
|
|
138
147
|
udef_to_blockkeys[("reg", base_off, base_reg_bits)].add((loc.block_addr, loc.block_idx))
|
|
139
148
|
# add a definition for the partial register
|
|
140
|
-
if base_off != def_.reg_offset:
|
|
149
|
+
if base_off != def_.reg_offset or base_size != def_.size:
|
|
141
150
|
reg_bits = def_.size * self.project.arch.byte_width
|
|
142
|
-
udef_to_defs[("reg", def_.reg_offset, reg_bits)].add(
|
|
151
|
+
udef_to_defs[("reg", def_.reg_offset, reg_bits)].add(def_)
|
|
152
|
+
udef_to_blockkeys[("reg", def_.reg_offset, reg_bits)].add((loc.block_addr, loc.block_idx))
|
|
143
153
|
elif isinstance(def_, Store):
|
|
144
154
|
if isinstance(def_.addr, StackBaseOffset) and isinstance(def_.addr.offset, int):
|
|
145
155
|
idx_begin = bisect_left(sorted_stackvar_offs, def_.addr.offset)
|
|
@@ -17,13 +17,24 @@ class TraversalAnalysis(ForwardAnalysis[TraversalState, ailment.Block, object, t
|
|
|
17
17
|
TraversalAnalysis traverses the AIL graph and collects definitions.
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
|
-
def __init__(
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
project,
|
|
23
|
+
func,
|
|
24
|
+
ail_graph,
|
|
25
|
+
sp_tracker,
|
|
26
|
+
bp_as_gpr: bool,
|
|
27
|
+
stackvars: bool,
|
|
28
|
+
tmps: bool,
|
|
29
|
+
func_args: set[ailment.Expr.VirtualVariable],
|
|
30
|
+
):
|
|
21
31
|
|
|
22
32
|
self.project = project
|
|
23
33
|
self._stackvars = stackvars
|
|
24
34
|
self._tmps = tmps
|
|
25
35
|
self._function = func
|
|
26
36
|
self._graph_visitor = FunctionGraphVisitor(self._function, ail_graph)
|
|
37
|
+
self._func_args = func_args
|
|
27
38
|
|
|
28
39
|
ForwardAnalysis.__init__(
|
|
29
40
|
self, order_jobs=True, allow_merging=True, allow_widening=False, graph_visitor=self._graph_visitor
|
|
@@ -52,13 +63,28 @@ class TraversalAnalysis(ForwardAnalysis[TraversalState, ailment.Block, object, t
|
|
|
52
63
|
pass
|
|
53
64
|
|
|
54
65
|
def _initial_abstract_state(self, node: ailment.Block) -> TraversalState:
|
|
55
|
-
|
|
66
|
+
state = TraversalState(self.project.arch, self._function)
|
|
67
|
+
# update it with function arguments
|
|
68
|
+
if self._func_args:
|
|
69
|
+
for func_arg in self._func_args:
|
|
70
|
+
if func_arg.oident[0] == ailment.Expr.VirtualVariableCategory.REGISTER:
|
|
71
|
+
reg_offset = func_arg.oident[1]
|
|
72
|
+
reg_size = func_arg.size
|
|
73
|
+
state.live_registers.add(reg_offset)
|
|
74
|
+
# get the full register if needed
|
|
75
|
+
basereg_offset, basereg_size = self.project.arch.get_base_register(reg_offset, size=reg_size)
|
|
76
|
+
if basereg_size != reg_size or basereg_offset != reg_offset:
|
|
77
|
+
state.live_registers.add(basereg_offset)
|
|
78
|
+
elif func_arg.oident[0] == ailment.Expr.VirtualVariableCategory.STACK:
|
|
79
|
+
state.live_stackvars.add((func_arg.oident[1], func_arg.size))
|
|
80
|
+
return state
|
|
56
81
|
|
|
57
82
|
def _merge_states(self, node: ailment.Block, *states: TraversalState) -> tuple[TraversalState, bool]:
|
|
58
83
|
merged_state = TraversalState(
|
|
59
84
|
self.project.arch,
|
|
60
85
|
self._function,
|
|
61
86
|
live_registers=states[0].live_registers.copy(),
|
|
87
|
+
live_stackvars=states[0].live_stackvars.copy(),
|
|
62
88
|
)
|
|
63
89
|
merge_occurred = merged_state.merge(*states[1:])
|
|
64
90
|
return merged_state, not merge_occurred
|
|
@@ -37,7 +37,12 @@ class TraversalState:
|
|
|
37
37
|
merge_occurred = True
|
|
38
38
|
all_regs |= o.live_registers
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
all_stackvars: set[tuple[int, int]] = self.live_stackvars.copy()
|
|
41
|
+
for o in others:
|
|
42
|
+
if o.live_stackvars.difference(all_stackvars):
|
|
43
|
+
merge_occurred = True
|
|
44
|
+
all_stackvars |= o.live_stackvars
|
|
41
45
|
|
|
42
46
|
self.live_registers = all_regs
|
|
47
|
+
self.live_stackvars = all_stackvars
|
|
43
48
|
return merge_occurred
|