angr 9.2.136__py3-none-manylinux2014_aarch64.whl → 9.2.137__py3-none-manylinux2014_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +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-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 +59 -58
- {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
angr/analyses/s_propagator.py
CHANGED
|
@@ -17,7 +17,7 @@ from ailment.expression import (
|
|
|
17
17
|
from ailment.statement import Assignment, Store, Return, Jump
|
|
18
18
|
|
|
19
19
|
from angr.knowledge_plugins.functions import Function
|
|
20
|
-
from angr.code_location import CodeLocation
|
|
20
|
+
from angr.code_location import CodeLocation, ExternalCodeLocation
|
|
21
21
|
from angr.analyses import Analysis, register_analysis
|
|
22
22
|
from angr.utils.ssa import (
|
|
23
23
|
get_vvar_uselocs,
|
|
@@ -54,6 +54,7 @@ class SPropagatorAnalysis(Analysis):
|
|
|
54
54
|
func_graph=None,
|
|
55
55
|
only_consts: bool = True,
|
|
56
56
|
stack_pointer_tracker=None,
|
|
57
|
+
func_args: set[VirtualVariable] | None = None,
|
|
57
58
|
func_addr: int | None = None,
|
|
58
59
|
):
|
|
59
60
|
if isinstance(subject, Block):
|
|
@@ -69,6 +70,7 @@ class SPropagatorAnalysis(Analysis):
|
|
|
69
70
|
|
|
70
71
|
self.func_graph = func_graph
|
|
71
72
|
self.func_addr = func_addr
|
|
73
|
+
self.func_args = func_args
|
|
72
74
|
self.only_consts = only_consts
|
|
73
75
|
self._sp_tracker = stack_pointer_tracker
|
|
74
76
|
|
|
@@ -109,6 +111,11 @@ class SPropagatorAnalysis(Analysis):
|
|
|
109
111
|
# find all vvar uses
|
|
110
112
|
vvar_uselocs = get_vvar_uselocs(blocks.values())
|
|
111
113
|
|
|
114
|
+
# update vvar_deflocs using function arguments
|
|
115
|
+
if self.func_args:
|
|
116
|
+
for func_arg in self.func_args:
|
|
117
|
+
vvar_deflocs[func_arg] = ExternalCodeLocation()
|
|
118
|
+
|
|
112
119
|
# find all ret sites and indirect jump sites
|
|
113
120
|
retsites: set[tuple[int, int | None, int]] = set()
|
|
114
121
|
jumpsites: set[tuple[int, int | None, int]] = set()
|
|
@@ -130,8 +137,9 @@ class SPropagatorAnalysis(Analysis):
|
|
|
130
137
|
|
|
131
138
|
vvarid_to_vvar[vvar.varid] = vvar
|
|
132
139
|
defloc = vvar_deflocs[vvar]
|
|
133
|
-
|
|
134
|
-
|
|
140
|
+
if isinstance(defloc, ExternalCodeLocation):
|
|
141
|
+
continue
|
|
142
|
+
|
|
135
143
|
block = blocks[(defloc.block_addr, defloc.block_idx)]
|
|
136
144
|
stmt = block.statements[defloc.stmt_idx]
|
|
137
145
|
r, v = is_const_assignment(stmt)
|
|
@@ -179,7 +187,20 @@ class SPropagatorAnalysis(Analysis):
|
|
|
179
187
|
continue
|
|
180
188
|
|
|
181
189
|
if is_const_and_vvar_assignment(stmt):
|
|
182
|
-
|
|
190
|
+
# if the useloc is a phi assignment statement, ensure that stmt.src is the same as the phi
|
|
191
|
+
# variable
|
|
192
|
+
useloc_stmt = blocks[(vvar_useloc.block_addr, vvar_useloc.block_idx)].statements[
|
|
193
|
+
vvar_useloc.stmt_idx
|
|
194
|
+
]
|
|
195
|
+
if is_phi_assignment(useloc_stmt):
|
|
196
|
+
if (
|
|
197
|
+
isinstance(stmt.src, VirtualVariable)
|
|
198
|
+
and stmt.src.oident == useloc_stmt.dst.oident
|
|
199
|
+
and stmt.src.category == useloc_stmt.dst.category
|
|
200
|
+
):
|
|
201
|
+
replacements[vvar_useloc][vvar_used] = stmt.src
|
|
202
|
+
else:
|
|
203
|
+
replacements[vvar_useloc][vvar_used] = stmt.src
|
|
183
204
|
continue
|
|
184
205
|
|
|
185
206
|
elif (
|
|
@@ -15,8 +15,9 @@ class SRDAModel:
|
|
|
15
15
|
The model for SRDA.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
def __init__(self, func_graph, arch):
|
|
18
|
+
def __init__(self, func_graph, func_args, arch):
|
|
19
19
|
self.func_graph = func_graph
|
|
20
|
+
self.func_args = func_args
|
|
20
21
|
self.arch = arch
|
|
21
22
|
self.varid_to_vvar: dict[int, VirtualVariable] = {}
|
|
22
23
|
self.all_vvar_definitions: dict[VirtualVariable, CodeLocation] = {}
|
|
@@ -4,7 +4,7 @@ import logging
|
|
|
4
4
|
from collections import defaultdict
|
|
5
5
|
|
|
6
6
|
from ailment.statement import Statement, Assignment, Call, Label
|
|
7
|
-
from ailment.expression import VirtualVariable, Expression
|
|
7
|
+
from ailment.expression import VirtualVariable, VirtualVariableCategory, Expression
|
|
8
8
|
|
|
9
9
|
from angr.utils.ail import is_phi_assignment
|
|
10
10
|
from angr.utils.graph import GraphUtils
|
|
@@ -133,6 +133,16 @@ class SRDAView:
|
|
|
133
133
|
predicater = RegVVarPredicate(reg_offset, vvars, self.model.arch)
|
|
134
134
|
self._get_vvar_by_stmt(block_addr, block_idx, stmt_idx, op_type, predicater.predicate)
|
|
135
135
|
|
|
136
|
+
if not vvars:
|
|
137
|
+
# not found - check function arguments
|
|
138
|
+
for func_arg in self.model.func_args:
|
|
139
|
+
if isinstance(func_arg, VirtualVariable):
|
|
140
|
+
func_arg_category = func_arg.oident[0]
|
|
141
|
+
if func_arg_category == VirtualVariableCategory.REGISTER:
|
|
142
|
+
func_arg_regoff = func_arg.oident[1]
|
|
143
|
+
if func_arg_regoff == reg_offset:
|
|
144
|
+
vvars.add(func_arg)
|
|
145
|
+
|
|
136
146
|
assert len(vvars) <= 1
|
|
137
147
|
return next(iter(vvars), None)
|
|
138
148
|
|
|
@@ -149,6 +159,15 @@ class SRDAView:
|
|
|
149
159
|
predicater = StackVVarPredicate(stack_offset, size, vvars)
|
|
150
160
|
self._get_vvar_by_stmt(block_addr, block_idx, stmt_idx, op_type, predicater.predicate)
|
|
151
161
|
|
|
162
|
+
if not vvars:
|
|
163
|
+
# not found - check function arguments
|
|
164
|
+
for func_arg in self.model.func_args:
|
|
165
|
+
if isinstance(func_arg, VirtualVariable):
|
|
166
|
+
func_arg_category = func_arg.oident[0]
|
|
167
|
+
if func_arg_category == VirtualVariableCategory.STACK:
|
|
168
|
+
func_arg_stackoff = func_arg.oident[1]
|
|
169
|
+
if func_arg_stackoff == stack_offset and func_arg.size == size:
|
|
170
|
+
vvars.add(func_arg)
|
|
152
171
|
assert len(vvars) <= 1
|
|
153
172
|
return next(iter(vvars), None)
|
|
154
173
|
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from ailment.block import Block
|
|
4
4
|
from ailment.statement import Assignment, Call, Return
|
|
5
|
+
from ailment.expression import VirtualVariable
|
|
5
6
|
import networkx
|
|
6
7
|
|
|
7
8
|
from angr.knowledge_plugins.functions import Function
|
|
@@ -24,6 +25,7 @@ class SReachingDefinitionsAnalysis(Analysis):
|
|
|
24
25
|
subject,
|
|
25
26
|
func_addr: int | None = None,
|
|
26
27
|
func_graph: networkx.DiGraph[Block] | None = None,
|
|
28
|
+
func_args: set[VirtualVariable] | None = None,
|
|
27
29
|
track_tmps: bool = False,
|
|
28
30
|
):
|
|
29
31
|
if isinstance(subject, Block):
|
|
@@ -39,13 +41,14 @@ class SReachingDefinitionsAnalysis(Analysis):
|
|
|
39
41
|
|
|
40
42
|
self.func_graph = func_graph
|
|
41
43
|
self.func_addr = func_addr if func_addr is not None else self.func.addr if self.func is not None else None
|
|
44
|
+
self.func_args = func_args
|
|
42
45
|
self._track_tmps = track_tmps
|
|
43
46
|
|
|
44
47
|
self._bp_as_gpr = False
|
|
45
48
|
if self.func is not None:
|
|
46
49
|
self._bp_as_gpr = self.func.info.get("bp_as_gpr", False)
|
|
47
50
|
|
|
48
|
-
self.model = SRDAModel(func_graph, self.project.arch)
|
|
51
|
+
self.model = SRDAModel(func_graph, func_args, self.project.arch)
|
|
49
52
|
|
|
50
53
|
self._analyze()
|
|
51
54
|
|
|
@@ -66,6 +69,13 @@ class SReachingDefinitionsAnalysis(Analysis):
|
|
|
66
69
|
# find all explicit vvar uses
|
|
67
70
|
vvar_uselocs = get_vvar_uselocs(blocks.values())
|
|
68
71
|
|
|
72
|
+
# update vvar definitions using function arguments
|
|
73
|
+
if self.func_args:
|
|
74
|
+
for vvar in self.func_args:
|
|
75
|
+
if vvar not in vvar_deflocs:
|
|
76
|
+
vvar_deflocs[vvar] = ExternalCodeLocation()
|
|
77
|
+
self.model.func_args = self.func_args
|
|
78
|
+
|
|
69
79
|
# update model
|
|
70
80
|
for vvar, defloc in vvar_deflocs.items():
|
|
71
81
|
self.model.varid_to_vvar[vvar.varid] = vvar
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
from typing import Any, TYPE_CHECKING
|
|
5
|
+
import contextlib
|
|
5
6
|
import re
|
|
6
7
|
import logging
|
|
7
8
|
from collections import defaultdict
|
|
@@ -15,7 +16,6 @@ from angr.knowledge_plugins import Function
|
|
|
15
16
|
from angr.block import BlockNode
|
|
16
17
|
from angr.errors import SimTranslationError
|
|
17
18
|
from .analysis import Analysis
|
|
18
|
-
import contextlib
|
|
19
19
|
|
|
20
20
|
try:
|
|
21
21
|
import pypcode
|
|
@@ -702,21 +702,31 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
|
|
|
702
702
|
# who are we calling?
|
|
703
703
|
callees = [] if self._func is None else self._find_callees(node)
|
|
704
704
|
if callees:
|
|
705
|
-
if (
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
and self.project.arch.name == "AMD64"
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
705
|
+
if len(callees) == 1:
|
|
706
|
+
callee = callees[0]
|
|
707
|
+
|
|
708
|
+
if callee.info.get("is_rust_probestack", False) is True and self.project.arch.name == "AMD64":
|
|
709
|
+
# special-case for rust_probestack: sp = sp - rax right after returning from the call, so we
|
|
710
|
+
# need to keep track of rax
|
|
711
|
+
for stmt in reversed(vex_block.statements):
|
|
712
|
+
if (
|
|
713
|
+
isinstance(stmt, pyvex.IRStmt.Put)
|
|
714
|
+
and stmt.offset == self.project.arch.registers["rax"][0]
|
|
715
|
+
and isinstance(stmt.data, pyvex.IRExpr.Const)
|
|
716
|
+
):
|
|
717
|
+
state.put(stmt.offset, Constant(stmt.data.con.value), force=True)
|
|
718
|
+
break
|
|
719
|
+
elif callee.name == "__chkstk":
|
|
720
|
+
# special-case for __chkstk: sp = sp - rax right after returning from the call, so we need to
|
|
721
|
+
# keep track of rax
|
|
722
|
+
for stmt in reversed(vex_block.statements):
|
|
723
|
+
if (
|
|
724
|
+
isinstance(stmt, pyvex.IRStmt.Put)
|
|
725
|
+
and stmt.offset == self.project.arch.registers["rax"][0]
|
|
726
|
+
and isinstance(stmt.data, pyvex.IRExpr.Const)
|
|
727
|
+
):
|
|
728
|
+
state.put(stmt.offset, Constant(stmt.data.con.value), force=True)
|
|
729
|
+
break
|
|
720
730
|
|
|
721
731
|
callee_cleanups = [
|
|
722
732
|
callee
|
|
@@ -74,17 +74,28 @@ class SimEngineVRAIL(
|
|
|
74
74
|
|
|
75
75
|
elif dst_type is ailment.Expr.VirtualVariable:
|
|
76
76
|
data = self._expr(stmt.src)
|
|
77
|
-
self._assign_to_vvar(
|
|
77
|
+
variable = self._assign_to_vvar(
|
|
78
78
|
stmt.dst, data, src=stmt.src, dst=stmt.dst, vvar_id=self._mapped_vvarid(stmt.dst.varid)
|
|
79
79
|
)
|
|
80
80
|
|
|
81
|
+
if variable is not None and isinstance(stmt.src, ailment.Expr.Phi):
|
|
82
|
+
# this is a phi node - we update variable manager's phi variable tracking
|
|
83
|
+
for _, vvar in stmt.src.src_and_vvars:
|
|
84
|
+
if vvar is not None:
|
|
85
|
+
r = self._read_from_vvar(vvar, expr=stmt.src, vvar_id=self._mapped_vvarid(vvar.varid))
|
|
86
|
+
if r.variable is not None:
|
|
87
|
+
pv = self.variable_manager[self.func_addr]._phi_variables
|
|
88
|
+
if variable not in pv:
|
|
89
|
+
pv[variable] = set()
|
|
90
|
+
pv[variable].add(r.variable)
|
|
91
|
+
|
|
81
92
|
if stmt.dst.was_stack and isinstance(stmt.dst.stack_offset, int):
|
|
82
93
|
# store it to the stack region in case it's directly referenced later
|
|
83
94
|
self._store(
|
|
84
95
|
RichR(self.state.stack_address(stmt.dst.stack_offset)),
|
|
85
96
|
data,
|
|
86
97
|
stmt.dst.bits // self.arch.byte_width,
|
|
87
|
-
|
|
98
|
+
atom=stmt.dst,
|
|
88
99
|
)
|
|
89
100
|
|
|
90
101
|
else:
|
|
@@ -94,10 +105,11 @@ class SimEngineVRAIL(
|
|
|
94
105
|
addr_r = self._expr_bv(stmt.addr)
|
|
95
106
|
data = self._expr(stmt.data)
|
|
96
107
|
size = stmt.size
|
|
97
|
-
self._store(addr_r, data, size,
|
|
108
|
+
self._store(addr_r, data, size, atom=stmt)
|
|
98
109
|
|
|
99
|
-
def _handle_stmt_Jump(self, stmt):
|
|
100
|
-
|
|
110
|
+
def _handle_stmt_Jump(self, stmt: ailment.Stmt.Jump):
|
|
111
|
+
if not isinstance(stmt.target, ailment.Expr.Const):
|
|
112
|
+
self._expr(stmt.target)
|
|
101
113
|
|
|
102
114
|
def _handle_stmt_ConditionalJump(self, stmt):
|
|
103
115
|
self._expr(stmt.condition)
|
|
@@ -149,7 +161,7 @@ class SimEngineVRAIL(
|
|
|
149
161
|
prototype_libname = func.prototype_libname
|
|
150
162
|
|
|
151
163
|
# dump the type of the return value
|
|
152
|
-
ret_ty = typevars.TypeVariable()
|
|
164
|
+
ret_ty = typevars.TypeVariable()
|
|
153
165
|
if isinstance(ret_ty, typeconsts.BottomType):
|
|
154
166
|
ret_ty = typevars.TypeVariable()
|
|
155
167
|
|
|
@@ -218,7 +230,7 @@ class SimEngineVRAIL(
|
|
|
218
230
|
prototype_libname = func.prototype_libname
|
|
219
231
|
|
|
220
232
|
# dump the type of the return value
|
|
221
|
-
ret_ty = typevars.TypeVariable()
|
|
233
|
+
ret_ty = typevars.TypeVariable()
|
|
222
234
|
if isinstance(ret_ty, typeconsts.BottomType):
|
|
223
235
|
ret_ty = typevars.TypeVariable()
|
|
224
236
|
|
|
@@ -387,7 +387,7 @@ class SimEngineVRBase(
|
|
|
387
387
|
) or not create_variable:
|
|
388
388
|
# only store the value. don't worry about variables.
|
|
389
389
|
self.vvar_region[vvar_id] = richr.data
|
|
390
|
-
return
|
|
390
|
+
return None
|
|
391
391
|
|
|
392
392
|
codeloc: CodeLocation = self._codeloc()
|
|
393
393
|
data = richr.data
|
|
@@ -463,10 +463,14 @@ class SimEngineVRBase(
|
|
|
463
463
|
else:
|
|
464
464
|
typevar = self.state.typevars.get_type_variable(variable, codeloc)
|
|
465
465
|
self.state.add_type_constraint(typevars.Subtype(richr.typevar, typevar))
|
|
466
|
+
# the constraint below is a default constraint that may conflict with more specific ones with different
|
|
467
|
+
# sizes; we post-process at the very end of VRA to remove conflicting default constraints.
|
|
466
468
|
self.state.add_type_constraint(typevars.Subtype(typevar, typeconsts.int_type(variable.size * 8)))
|
|
467
469
|
|
|
470
|
+
return variable
|
|
471
|
+
|
|
468
472
|
def _store(
|
|
469
|
-
self, richr_addr: RichR[claripy.ast.BV], data: RichR[claripy.ast.BV | claripy.ast.FP], size,
|
|
473
|
+
self, richr_addr: RichR[claripy.ast.BV], data: RichR[claripy.ast.BV | claripy.ast.FP], size, atom=None
|
|
470
474
|
): # pylint:disable=unused-argument
|
|
471
475
|
"""
|
|
472
476
|
|
|
@@ -481,19 +485,19 @@ class SimEngineVRBase(
|
|
|
481
485
|
|
|
482
486
|
if addr.concrete:
|
|
483
487
|
# fully concrete. this is a global address
|
|
484
|
-
self._store_to_global(addr.concrete_value, data, size, stmt=
|
|
488
|
+
self._store_to_global(addr.concrete_value, data, size, stmt=atom)
|
|
485
489
|
stored = True
|
|
486
490
|
elif self._addr_has_concrete_base(addr) and (parsed := self._parse_offsetted_addr(addr)) is not None:
|
|
487
491
|
# we are storing to a concrete global address with an offset
|
|
488
492
|
base_addr, offset, elem_size = parsed
|
|
489
|
-
self._store_to_global(base_addr.concrete_value, data, size, stmt=
|
|
493
|
+
self._store_to_global(base_addr.concrete_value, data, size, stmt=atom, offset=offset, elem_size=elem_size)
|
|
490
494
|
stored = True
|
|
491
495
|
else:
|
|
492
496
|
if self.state.is_stack_address(addr):
|
|
493
497
|
stack_offset = self.state.get_stack_offset(addr)
|
|
494
498
|
if stack_offset is not None:
|
|
495
499
|
# fast path: Storing data to stack
|
|
496
|
-
self._store_to_stack(stack_offset, data, size,
|
|
500
|
+
self._store_to_stack(stack_offset, data, size, atom=atom)
|
|
497
501
|
stored = True
|
|
498
502
|
|
|
499
503
|
if not stored:
|
|
@@ -504,21 +508,21 @@ class SimEngineVRBase(
|
|
|
504
508
|
codeloc = self._codeloc()
|
|
505
509
|
if existing_vars:
|
|
506
510
|
for existing_var, _ in list(existing_vars):
|
|
507
|
-
self.variable_manager[self.func_addr].remove_variable_by_atom(codeloc, existing_var,
|
|
511
|
+
self.variable_manager[self.func_addr].remove_variable_by_atom(codeloc, existing_var, atom)
|
|
508
512
|
|
|
509
513
|
# storing to a location specified by a pointer whose value cannot be determined at this point
|
|
510
|
-
self._store_to_variable(richr_addr, size
|
|
514
|
+
self._store_to_variable(richr_addr, size)
|
|
511
515
|
|
|
512
516
|
def _store_to_stack(
|
|
513
|
-
self, stack_offset, data: RichR[claripy.ast.BV | claripy.ast.FP], size, offset=0,
|
|
517
|
+
self, stack_offset, data: RichR[claripy.ast.BV | claripy.ast.FP], size, offset=0, atom=None, endness=None
|
|
514
518
|
):
|
|
515
|
-
if
|
|
519
|
+
if atom is None:
|
|
516
520
|
existing_vars = self.variable_manager[self.func_addr].find_variables_by_stmt(
|
|
517
521
|
self.block.addr, self.stmt_idx, "memory"
|
|
518
522
|
)
|
|
519
523
|
else:
|
|
520
524
|
existing_vars = self.variable_manager[self.func_addr].find_variables_by_atom(
|
|
521
|
-
self.block.addr, self.stmt_idx,
|
|
525
|
+
self.block.addr, self.stmt_idx, atom
|
|
522
526
|
)
|
|
523
527
|
if not existing_vars:
|
|
524
528
|
variable = SimStackVariable(
|
|
@@ -562,7 +566,7 @@ class SimEngineVRBase(
|
|
|
562
566
|
var,
|
|
563
567
|
offset_into_var,
|
|
564
568
|
codeloc,
|
|
565
|
-
atom=
|
|
569
|
+
atom=atom,
|
|
566
570
|
)
|
|
567
571
|
|
|
568
572
|
# create type constraints
|
|
@@ -673,9 +677,7 @@ class SimEngineVRBase(
|
|
|
673
677
|
self.state.add_type_constraint(typevars.Subtype(store_typevar, typeconsts.TopType()))
|
|
674
678
|
self.state.add_type_constraint(typevars.Subtype(data.typevar, store_typevar))
|
|
675
679
|
|
|
676
|
-
def _store_to_variable(
|
|
677
|
-
self, richr_addr: RichR[claripy.ast.BV], size: int, stmt=None
|
|
678
|
-
): # pylint:disable=unused-argument
|
|
680
|
+
def _store_to_variable(self, richr_addr: RichR[claripy.ast.BV], size: int):
|
|
679
681
|
addr_variable = richr_addr.variable
|
|
680
682
|
codeloc = self._codeloc()
|
|
681
683
|
|
|
@@ -74,7 +74,7 @@ class SimEngineVRVEX(
|
|
|
74
74
|
size = stmt.data.result_size(self.tyenv) // 8
|
|
75
75
|
r = self._expr(stmt.data)
|
|
76
76
|
|
|
77
|
-
self._store(addr_r, r, size,
|
|
77
|
+
self._store(addr_r, r, size, atom=stmt)
|
|
78
78
|
|
|
79
79
|
def _handle_stmt_StoreG(self, stmt):
|
|
80
80
|
guard = self._expr(stmt.guard)
|
|
@@ -82,7 +82,7 @@ class SimEngineVRVEX(
|
|
|
82
82
|
addr = self._expr_bv(stmt.addr)
|
|
83
83
|
size = stmt.data.result_size(self.tyenv) // 8
|
|
84
84
|
data = self._expr(stmt.data)
|
|
85
|
-
self._store(addr, data, size,
|
|
85
|
+
self._store(addr, data, size, atom=stmt)
|
|
86
86
|
|
|
87
87
|
def _handle_stmt_LoadG(self, stmt):
|
|
88
88
|
guard = self._expr(stmt.guard)
|
|
@@ -20,7 +20,8 @@ from angr.knowledge_plugins import Function
|
|
|
20
20
|
from angr.sim_variable import SimStackVariable, SimRegisterVariable, SimVariable, SimMemoryVariable
|
|
21
21
|
from angr.engines.vex.claripy.irop import vexop_to_simop
|
|
22
22
|
from angr.analyses import ForwardAnalysis, visitors
|
|
23
|
-
from angr.analyses.typehoon.typevars import Equivalence, TypeVariable, TypeVariables
|
|
23
|
+
from angr.analyses.typehoon.typevars import Equivalence, TypeVariable, TypeVariables, Subtype, DerivedTypeVariable
|
|
24
|
+
from angr.analyses.typehoon.typeconsts import Int
|
|
24
25
|
from .variable_recovery_base import VariableRecoveryBase, VariableRecoveryStateBase
|
|
25
26
|
from .engine_vex import SimEngineVRVEX
|
|
26
27
|
from .engine_ail import SimEngineVRAIL
|
|
@@ -500,6 +501,26 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
500
501
|
for tv in sorted_typevars[1:]:
|
|
501
502
|
self.type_constraints[self.func_typevar].add(Equivalence(sorted_typevars[0], tv))
|
|
502
503
|
|
|
504
|
+
# remove default constraints with size conflicts
|
|
505
|
+
for func_var in self.type_constraints:
|
|
506
|
+
var_to_subtyping: dict[TypeVariable, list[Subtype]] = defaultdict(list)
|
|
507
|
+
for constraint in self.type_constraints[func_var]:
|
|
508
|
+
if isinstance(constraint, Subtype) and isinstance(constraint.sub_type, TypeVariable):
|
|
509
|
+
var_to_subtyping[constraint.sub_type].append(constraint)
|
|
510
|
+
|
|
511
|
+
for constraints in var_to_subtyping.values():
|
|
512
|
+
if len(constraints) <= 1:
|
|
513
|
+
continue
|
|
514
|
+
default_subtyping_constraints = set()
|
|
515
|
+
has_nondefault_subtyping_constraints = False
|
|
516
|
+
for constraint in constraints:
|
|
517
|
+
if isinstance(constraint.super_type, Int):
|
|
518
|
+
default_subtyping_constraints.add(constraint)
|
|
519
|
+
elif isinstance(constraint.super_type, DerivedTypeVariable) and constraint.super_type.labels:
|
|
520
|
+
has_nondefault_subtyping_constraints = True
|
|
521
|
+
if has_nondefault_subtyping_constraints:
|
|
522
|
+
self.type_constraints[func_var].difference_update(default_subtyping_constraints)
|
|
523
|
+
|
|
503
524
|
self.variable_manager[self.function.addr].ret_val_size = self.ret_val_size
|
|
504
525
|
|
|
505
526
|
self.delayed_type_constraints = None
|
angr/block.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# pylint:disable=wrong-import-position,arguments-differ
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
import logging
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
4
5
|
|
|
5
6
|
import pyvex
|
|
6
7
|
from pyvex import IRSB
|
|
7
|
-
from archinfo import ArchARM
|
|
8
|
+
from archinfo import Arch, ArchARM
|
|
8
9
|
|
|
9
10
|
from .protos import primitives_pb2 as pb2
|
|
10
11
|
from .serializable import Serializable
|
|
@@ -14,6 +15,12 @@ try:
|
|
|
14
15
|
except ImportError:
|
|
15
16
|
pcode = None
|
|
16
17
|
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from angr import Project
|
|
20
|
+
from angr.engines.vex import VEXLifter
|
|
21
|
+
from angr.engines.pcode.lifter import PcodeLifterEngineMixin, IRSB as PcodeIRSB
|
|
22
|
+
from angr.engines.soot.engine import SootMixin
|
|
23
|
+
|
|
17
24
|
|
|
18
25
|
l = logging.getLogger(name=__name__)
|
|
19
26
|
|
|
@@ -148,7 +155,7 @@ class Block(Serializable):
|
|
|
148
155
|
self,
|
|
149
156
|
addr,
|
|
150
157
|
project=None,
|
|
151
|
-
arch=None,
|
|
158
|
+
arch: Arch = None,
|
|
152
159
|
size=None,
|
|
153
160
|
max_size=None,
|
|
154
161
|
byte_string=None,
|
|
@@ -168,6 +175,7 @@ class Block(Serializable):
|
|
|
168
175
|
skip_stmts=False,
|
|
169
176
|
):
|
|
170
177
|
# set up arch
|
|
178
|
+
self.arch: Arch
|
|
171
179
|
if project is not None:
|
|
172
180
|
self.arch = project.arch
|
|
173
181
|
else:
|
|
@@ -187,7 +195,7 @@ class Block(Serializable):
|
|
|
187
195
|
else:
|
|
188
196
|
thumb = False
|
|
189
197
|
|
|
190
|
-
self._project = project
|
|
198
|
+
self._project: Project | None = project
|
|
191
199
|
self.thumb = thumb
|
|
192
200
|
self.addr = addr
|
|
193
201
|
self._opt_level = opt_level
|
|
@@ -206,8 +214,15 @@ class Block(Serializable):
|
|
|
206
214
|
else:
|
|
207
215
|
if self._initial_regs:
|
|
208
216
|
self.set_initial_regs()
|
|
217
|
+
clemory = None
|
|
218
|
+
if project is not None:
|
|
219
|
+
clemory = (
|
|
220
|
+
project.loader.memory_ro_view
|
|
221
|
+
if project.loader.memory_ro_view is not None
|
|
222
|
+
else project.loader.memory
|
|
223
|
+
)
|
|
209
224
|
vex = self._vex_engine.lift_vex(
|
|
210
|
-
clemory=
|
|
225
|
+
clemory=clemory,
|
|
211
226
|
state=backup_state,
|
|
212
227
|
insn_bytes=byte_string,
|
|
213
228
|
addr=addr,
|
|
@@ -243,7 +258,7 @@ class Block(Serializable):
|
|
|
243
258
|
self._load_from_ro_regions = load_from_ro_regions
|
|
244
259
|
self._const_prop = const_prop
|
|
245
260
|
|
|
246
|
-
self._instructions = num_inst
|
|
261
|
+
self._instructions: int | None = num_inst
|
|
247
262
|
self._instruction_addrs: list[int] = []
|
|
248
263
|
|
|
249
264
|
if skip_stmts:
|
|
@@ -258,7 +273,7 @@ class Block(Serializable):
|
|
|
258
273
|
if type(self._bytes) is memoryview:
|
|
259
274
|
self._bytes = bytes(self._bytes)
|
|
260
275
|
elif type(self._bytes) is not bytes:
|
|
261
|
-
self._bytes = bytes(pyvex.ffi.buffer(self._bytes, size))
|
|
276
|
+
self._bytes = bytes(pyvex.ffi.buffer(self._bytes, size)) # type:ignore
|
|
262
277
|
else:
|
|
263
278
|
self._bytes = None
|
|
264
279
|
elif type(byte_string) is bytes:
|
|
@@ -269,7 +284,7 @@ class Block(Serializable):
|
|
|
269
284
|
else:
|
|
270
285
|
# Convert bytestring to a str
|
|
271
286
|
# size will ALWAYS be known at this point
|
|
272
|
-
self._bytes =
|
|
287
|
+
self._bytes = bytes(pyvex.ffi.buffer(byte_string, self.size)) # type:ignore
|
|
273
288
|
|
|
274
289
|
def _parse_vex_info(self, vex_block):
|
|
275
290
|
if vex_block is not None:
|
|
@@ -323,16 +338,25 @@ class Block(Serializable):
|
|
|
323
338
|
pyvex.pvc.reset_initial_register_values()
|
|
324
339
|
|
|
325
340
|
@property
|
|
326
|
-
def _vex_engine(self):
|
|
327
|
-
|
|
341
|
+
def _vex_engine(self) -> VEXLifter | PcodeLifterEngineMixin:
|
|
342
|
+
if self._project is None:
|
|
343
|
+
raise ValueError("Project is not set")
|
|
344
|
+
return self._project.factory.default_engine # type:ignore
|
|
328
345
|
|
|
329
346
|
@property
|
|
330
|
-
def vex(self) -> IRSB:
|
|
347
|
+
def vex(self) -> IRSB | PcodeIRSB:
|
|
331
348
|
if not self._vex:
|
|
332
349
|
if self._initial_regs:
|
|
333
350
|
self.set_initial_regs()
|
|
351
|
+
clemory = None
|
|
352
|
+
if self._project is not None:
|
|
353
|
+
clemory = (
|
|
354
|
+
self._project.loader.memory_ro_view
|
|
355
|
+
if self._project.loader.memory_ro_view is not None
|
|
356
|
+
else self._project.loader.memory
|
|
357
|
+
)
|
|
334
358
|
self._vex = self._vex_engine.lift_vex(
|
|
335
|
-
clemory=
|
|
359
|
+
clemory=clemory,
|
|
336
360
|
insn_bytes=self._bytes,
|
|
337
361
|
addr=self.addr,
|
|
338
362
|
thumb=self.thumb,
|
|
@@ -350,6 +374,7 @@ class Block(Serializable):
|
|
|
350
374
|
self.reset_initial_regs()
|
|
351
375
|
self._parse_vex_info(self._vex)
|
|
352
376
|
|
|
377
|
+
assert self._vex is not None
|
|
353
378
|
return self._vex
|
|
354
379
|
|
|
355
380
|
@property
|
|
@@ -362,8 +387,15 @@ class Block(Serializable):
|
|
|
362
387
|
|
|
363
388
|
if self._initial_regs:
|
|
364
389
|
self.set_initial_regs()
|
|
390
|
+
clemory = None
|
|
391
|
+
if self._project is not None:
|
|
392
|
+
clemory = (
|
|
393
|
+
self._project.loader.memory_ro_view
|
|
394
|
+
if self._project.loader.memory_ro_view is not None
|
|
395
|
+
else self._project.loader.memory
|
|
396
|
+
)
|
|
365
397
|
self._vex_nostmt = self._vex_engine.lift_vex(
|
|
366
|
-
clemory=
|
|
398
|
+
clemory=clemory,
|
|
367
399
|
insn_bytes=self._bytes,
|
|
368
400
|
addr=self.addr,
|
|
369
401
|
thumb=self.thumb,
|
|
@@ -394,17 +426,17 @@ class Block(Serializable):
|
|
|
394
426
|
"""
|
|
395
427
|
if self._disassembly is None:
|
|
396
428
|
if self._using_pcode_engine:
|
|
397
|
-
self._disassembly = self.vex.disassembly
|
|
429
|
+
self._disassembly = self.vex.disassembly # type:ignore
|
|
398
430
|
else:
|
|
399
431
|
self._disassembly = self.capstone
|
|
400
432
|
return self._disassembly
|
|
401
433
|
|
|
402
434
|
@property
|
|
403
|
-
def capstone(self):
|
|
435
|
+
def capstone(self) -> CapstoneBlock:
|
|
404
436
|
if self._capstone:
|
|
405
437
|
return self._capstone
|
|
406
438
|
|
|
407
|
-
cs = self.arch.capstone if not self.thumb else self.arch.capstone_thumb
|
|
439
|
+
cs = self.arch.capstone if not self.thumb else self.arch.capstone_thumb # type:ignore
|
|
408
440
|
|
|
409
441
|
insns = []
|
|
410
442
|
|
|
@@ -423,12 +455,18 @@ class Block(Serializable):
|
|
|
423
455
|
return BlockNode(self.addr, self.size, bytestr=self.bytes, thumb=self.thumb)
|
|
424
456
|
|
|
425
457
|
@property
|
|
426
|
-
def bytes(self) -> bytes:
|
|
458
|
+
def bytes(self) -> bytes | None:
|
|
427
459
|
if self._bytes is None:
|
|
428
460
|
addr = self.addr
|
|
429
461
|
if self.thumb:
|
|
430
462
|
addr = (addr >> 1) << 1
|
|
431
|
-
|
|
463
|
+
if self._project is not None:
|
|
464
|
+
mem = (
|
|
465
|
+
self._project.loader.memory_ro_view
|
|
466
|
+
if self._project.loader.memory_ro_view is not None
|
|
467
|
+
else self._project.loader.memory
|
|
468
|
+
)
|
|
469
|
+
self._bytes = mem.load(addr, self.size)
|
|
432
470
|
return self._bytes
|
|
433
471
|
|
|
434
472
|
@property
|
|
@@ -437,6 +475,7 @@ class Block(Serializable):
|
|
|
437
475
|
# initialize from VEX
|
|
438
476
|
_ = self.vex
|
|
439
477
|
|
|
478
|
+
assert self._instructions is not None
|
|
440
479
|
return self._instructions
|
|
441
480
|
|
|
442
481
|
@property
|
|
@@ -477,17 +516,17 @@ class SootBlock:
|
|
|
477
516
|
Represents a Soot IR basic block.
|
|
478
517
|
"""
|
|
479
518
|
|
|
480
|
-
def __init__(self, addr, project
|
|
519
|
+
def __init__(self, addr, *, project: Project, arch: Arch):
|
|
481
520
|
self.addr = addr
|
|
482
521
|
self.arch = arch
|
|
483
522
|
self._project = project
|
|
484
523
|
self._the_binary = project.loader.main_object
|
|
485
524
|
|
|
486
525
|
@property
|
|
487
|
-
def _soot_engine(self):
|
|
526
|
+
def _soot_engine(self) -> SootMixin:
|
|
488
527
|
if self._project is None:
|
|
489
528
|
assert False, "This should be unreachable"
|
|
490
|
-
return self._project.factory.default_engine
|
|
529
|
+
return self._project.factory.default_engine # type:ignore
|
|
491
530
|
|
|
492
531
|
@property
|
|
493
532
|
def soot(self):
|
angr/engines/pcode/emulate.py
CHANGED