angr 9.2.139__py3-none-manylinux2014_aarch64.whl → 9.2.141__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 +136 -53
- angr/analyses/calling_convention/fact_collector.py +44 -18
- angr/analyses/calling_convention/utils.py +3 -1
- angr/analyses/cfg/cfg_base.py +13 -0
- angr/analyses/cfg/cfg_fast.py +11 -0
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +9 -8
- angr/analyses/decompiler/ail_simplifier.py +115 -72
- angr/analyses/decompiler/callsite_maker.py +24 -11
- angr/analyses/decompiler/clinic.py +78 -43
- angr/analyses/decompiler/decompiler.py +18 -7
- angr/analyses/decompiler/expression_narrower.py +1 -1
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +8 -7
- angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +3 -1
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +21 -2
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +21 -13
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +84 -15
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +92 -11
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +53 -9
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +44 -7
- angr/analyses/decompiler/region_identifier.py +6 -4
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +287 -122
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +31 -13
- angr/analyses/decompiler/ssailification/rewriting.py +23 -15
- angr/analyses/decompiler/ssailification/rewriting_engine.py +105 -24
- angr/analyses/decompiler/ssailification/ssailification.py +22 -14
- angr/analyses/decompiler/structured_codegen/c.py +73 -137
- angr/analyses/decompiler/structuring/dream.py +22 -18
- angr/analyses/decompiler/structuring/phoenix.py +158 -41
- angr/analyses/decompiler/structuring/recursive_structurer.py +1 -0
- angr/analyses/decompiler/structuring/structurer_base.py +37 -10
- angr/analyses/decompiler/structuring/structurer_nodes.py +4 -1
- angr/analyses/decompiler/utils.py +106 -21
- angr/analyses/deobfuscator/api_obf_finder.py +8 -5
- angr/analyses/deobfuscator/api_obf_type2_finder.py +18 -10
- 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 +6 -41
- angr/analyses/s_reaching_definitions/s_rda_model.py +7 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +43 -25
- 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 +7 -5
- angr/analyses/variable_recovery/engine_vex.py +20 -4
- angr/block.py +69 -107
- angr/callable.py +14 -7
- angr/calling_conventions.py +30 -11
- angr/distributed/__init__.py +1 -1
- angr/engines/__init__.py +7 -8
- angr/engines/engine.py +1 -120
- angr/engines/failure.py +2 -2
- angr/engines/hook.py +2 -2
- angr/engines/light/engine.py +2 -2
- angr/engines/pcode/engine.py +2 -14
- 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 +124 -11
- angr/engines/syscall.py +2 -2
- angr/engines/unicorn.py +3 -3
- angr/engines/vex/heavy/heavy.py +3 -15
- angr/factory.py +12 -22
- angr/knowledge_plugins/key_definitions/atoms.py +8 -4
- angr/knowledge_plugins/key_definitions/live_definitions.py +41 -103
- angr/knowledge_plugins/variables/variable_manager.py +7 -5
- angr/sim_type.py +19 -17
- angr/simos/simos.py +3 -1
- 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/utils/types.py +48 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/METADATA +6 -6
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/RECORD +87 -86
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/LICENSE +0 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/WHEEL +0 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/entry_points.txt +0 -0
- {angr-9.2.139.dist-info → angr-9.2.141.dist-info}/top_level.txt +0 -0
|
@@ -5,6 +5,7 @@ from collections import defaultdict
|
|
|
5
5
|
import logging
|
|
6
6
|
|
|
7
7
|
import networkx
|
|
8
|
+
from sortedcontainers import SortedDict
|
|
8
9
|
|
|
9
10
|
from angr.utils.constants import MAX_POINTSTO_BITS
|
|
10
11
|
from .typevars import (
|
|
@@ -1165,25 +1166,45 @@ class SimpleSolver:
|
|
|
1165
1166
|
# this might be a struct
|
|
1166
1167
|
fields = {}
|
|
1167
1168
|
|
|
1168
|
-
candidate_bases =
|
|
1169
|
+
candidate_bases = SortedDict()
|
|
1169
1170
|
|
|
1170
1171
|
for labels, _succ in path_and_successors:
|
|
1171
1172
|
last_label = labels[-1] if labels else None
|
|
1172
1173
|
if isinstance(last_label, HasField):
|
|
1173
1174
|
# TODO: Really determine the maximum possible size of the field when MAX_POINTSTO_BITS is in use
|
|
1175
|
+
if last_label.offset not in candidate_bases:
|
|
1176
|
+
candidate_bases[last_label.offset] = set()
|
|
1174
1177
|
candidate_bases[last_label.offset].add(
|
|
1175
1178
|
1 if last_label.bits == MAX_POINTSTO_BITS else (last_label.bits // 8)
|
|
1176
1179
|
)
|
|
1177
1180
|
|
|
1181
|
+
# determine possible bases and map each offset to its base
|
|
1182
|
+
offset_to_base = SortedDict()
|
|
1183
|
+
for start_offset, sizes in candidate_bases.items():
|
|
1184
|
+
for size in sizes:
|
|
1185
|
+
for i in range(size):
|
|
1186
|
+
access_off = start_offset + i
|
|
1187
|
+
if access_off not in offset_to_base:
|
|
1188
|
+
offset_to_base[access_off] = start_offset
|
|
1189
|
+
|
|
1190
|
+
# determine again the maximum size of each field (at each offset)
|
|
1191
|
+
offset_to_maxsize = defaultdict(int)
|
|
1192
|
+
offset_to_sizes = defaultdict(set) # we do not consider offsets to each base offset
|
|
1193
|
+
for labels, _succ in path_and_successors:
|
|
1194
|
+
last_label = labels[-1] if labels else None
|
|
1195
|
+
if isinstance(last_label, HasField):
|
|
1196
|
+
base = offset_to_base[last_label.offset]
|
|
1197
|
+
access_size = 1 if last_label.bits == MAX_POINTSTO_BITS else (last_label.bits // 8)
|
|
1198
|
+
offset_to_maxsize[base] = max(offset_to_maxsize[base], (last_label.offset - base) + access_size)
|
|
1199
|
+
offset_to_sizes[base].add(access_size)
|
|
1200
|
+
|
|
1178
1201
|
node_to_base = {}
|
|
1179
1202
|
|
|
1180
1203
|
for labels, succ in path_and_successors:
|
|
1181
1204
|
last_label = labels[-1] if labels else None
|
|
1182
1205
|
if isinstance(last_label, HasField):
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
if last_label.offset > start_offset and last_label.offset < start_offset + size: # ???
|
|
1186
|
-
node_to_base[succ] = start_offset
|
|
1206
|
+
prev_offset = next(offset_to_base.irange(maximum=last_label.offset, reverse=True))
|
|
1207
|
+
node_to_base[succ] = offset_to_base[prev_offset]
|
|
1187
1208
|
|
|
1188
1209
|
node_by_offset = defaultdict(set)
|
|
1189
1210
|
|
|
@@ -1195,16 +1216,33 @@ class SimpleSolver:
|
|
|
1195
1216
|
else:
|
|
1196
1217
|
node_by_offset[last_label.offset].add(succ)
|
|
1197
1218
|
|
|
1198
|
-
|
|
1219
|
+
sorted_offsets: list[int] = sorted(node_by_offset)
|
|
1220
|
+
for i in range(len(sorted_offsets)): # pylint:disable=consider-using-enumerate
|
|
1221
|
+
offset = sorted_offsets[i]
|
|
1222
|
+
|
|
1223
|
+
child_nodes = node_by_offset[offset]
|
|
1199
1224
|
sol = self._determine(equivalent_classes, the_typevar, sketch, solution, nodes=child_nodes)
|
|
1200
1225
|
if isinstance(sol, TopType):
|
|
1201
|
-
|
|
1226
|
+
# make it an array if possible
|
|
1227
|
+
elem_size = min(offset_to_sizes[offset])
|
|
1228
|
+
array_size = offset_to_maxsize[offset]
|
|
1229
|
+
if array_size % elem_size != 0:
|
|
1230
|
+
# fall back to byte_t
|
|
1231
|
+
elem_size = 1
|
|
1232
|
+
elem_type = int_type(elem_size * 8)
|
|
1233
|
+
sol = elem_type if array_size == elem_size else Array(elem_type, array_size // elem_size)
|
|
1202
1234
|
fields[offset] = sol
|
|
1203
1235
|
|
|
1204
1236
|
if not fields:
|
|
1205
1237
|
result = Top_
|
|
1206
1238
|
for node in nodes:
|
|
1207
1239
|
self._solution_cache[node.typevar] = result
|
|
1240
|
+
solution[node.typevar] = result
|
|
1241
|
+
elif any(off < 0 for off in fields):
|
|
1242
|
+
result = self._pointer_class()(Bottom_)
|
|
1243
|
+
for node in nodes:
|
|
1244
|
+
self._solution_cache[node.typevar] = result
|
|
1245
|
+
solution[node.typevar] = result
|
|
1208
1246
|
else:
|
|
1209
1247
|
# back-patch
|
|
1210
1248
|
struct_type.fields = fields
|
|
@@ -42,7 +42,7 @@ class TypeConstant:
|
|
|
42
42
|
raise NotImplementedError
|
|
43
43
|
return self.SIZE
|
|
44
44
|
|
|
45
|
-
def __repr__(self, memo=None):
|
|
45
|
+
def __repr__(self, memo=None) -> str:
|
|
46
46
|
raise NotImplementedError
|
|
47
47
|
|
|
48
48
|
|
|
@@ -57,7 +57,7 @@ class BottomType(TypeConstant):
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
class Int(TypeConstant):
|
|
60
|
-
def __repr__(self, memo=None):
|
|
60
|
+
def __repr__(self, memo=None) -> str:
|
|
61
61
|
return "intbase"
|
|
62
62
|
|
|
63
63
|
|
|
@@ -82,14 +82,14 @@ class Int16(Int):
|
|
|
82
82
|
class Int32(Int):
|
|
83
83
|
SIZE = 4
|
|
84
84
|
|
|
85
|
-
def __repr__(self, memo=None):
|
|
85
|
+
def __repr__(self, memo=None) -> str:
|
|
86
86
|
return "int32"
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
class Int64(Int):
|
|
90
90
|
SIZE = 8
|
|
91
91
|
|
|
92
|
-
def __repr__(self, memo=None):
|
|
92
|
+
def __repr__(self, memo=None) -> str:
|
|
93
93
|
return "int64"
|
|
94
94
|
|
|
95
95
|
|
|
@@ -115,7 +115,7 @@ class Int512(Int):
|
|
|
115
115
|
|
|
116
116
|
|
|
117
117
|
class FloatBase(TypeConstant):
|
|
118
|
-
def __repr__(self, memo=None):
|
|
118
|
+
def __repr__(self, memo=None) -> str:
|
|
119
119
|
return "floatbase"
|
|
120
120
|
|
|
121
121
|
|
|
@@ -185,6 +185,12 @@ class Array(TypeConstant):
|
|
|
185
185
|
self.element: TypeConstant | None = element
|
|
186
186
|
self.count: int | None = count
|
|
187
187
|
|
|
188
|
+
@property
|
|
189
|
+
def size(self) -> int:
|
|
190
|
+
if not self.count or not self.element:
|
|
191
|
+
return 0
|
|
192
|
+
return self.element.size * self.count
|
|
193
|
+
|
|
188
194
|
@memoize
|
|
189
195
|
def __repr__(self, memo=None):
|
|
190
196
|
if self.count is None:
|
|
@@ -221,6 +227,13 @@ class Struct(TypeConstant):
|
|
|
221
227
|
tpl = tuple((k, self.fields[k]._hash(visited) if self.fields[k] is not None else None) for k in keys)
|
|
222
228
|
return hash(tpl)
|
|
223
229
|
|
|
230
|
+
@property
|
|
231
|
+
def size(self) -> int:
|
|
232
|
+
if not self.fields:
|
|
233
|
+
return 0
|
|
234
|
+
max_field_off = max(self.fields.keys())
|
|
235
|
+
return max_field_off + self.fields[max_field_off].size
|
|
236
|
+
|
|
224
237
|
@memoize
|
|
225
238
|
def __repr__(self, memo=None):
|
|
226
239
|
prefix = "struct"
|
|
@@ -333,7 +333,7 @@ class SimEngineVRAIL(
|
|
|
333
333
|
tvs = set()
|
|
334
334
|
for _, vvar in expr.src_and_vvars:
|
|
335
335
|
if vvar is not None:
|
|
336
|
-
r = self._read_from_vvar(vvar, expr=
|
|
336
|
+
r = self._read_from_vvar(vvar, expr=vvar, vvar_id=self._mapped_vvarid(vvar.varid))
|
|
337
337
|
if r.typevar is not None:
|
|
338
338
|
tvs.add(r.typevar)
|
|
339
339
|
|
|
@@ -430,6 +430,7 @@ class SimEngineVRBase(
|
|
|
430
430
|
self.state.variable_manager[self.func_addr].add_variable("register", vvar.oident, variable)
|
|
431
431
|
elif vvar.was_tmp:
|
|
432
432
|
# FIXME: we treat all tmp vvars as registers
|
|
433
|
+
assert vvar.tmp_idx is not None
|
|
433
434
|
variable = SimRegisterVariable(
|
|
434
435
|
4096 + vvar.tmp_idx,
|
|
435
436
|
vvar.size,
|
|
@@ -503,7 +504,7 @@ class SimEngineVRBase(
|
|
|
503
504
|
self.state.variable_manager[self.func_addr].remove_variable_by_atom(codeloc, existing_var, atom)
|
|
504
505
|
|
|
505
506
|
# storing to a location specified by a pointer whose value cannot be determined at this point
|
|
506
|
-
self._store_to_variable(richr_addr, size)
|
|
507
|
+
self._store_to_variable(richr_addr, data, size)
|
|
507
508
|
|
|
508
509
|
def _store_to_stack(
|
|
509
510
|
self, stack_offset, data: RichR[claripy.ast.BV | claripy.ast.FP], size, offset=0, atom=None, endness=None
|
|
@@ -669,7 +670,7 @@ class SimEngineVRBase(
|
|
|
669
670
|
self.state.add_type_constraint(typevars.Subtype(store_typevar, typeconsts.TopType()))
|
|
670
671
|
self.state.add_type_constraint(typevars.Subtype(data.typevar, store_typevar))
|
|
671
672
|
|
|
672
|
-
def _store_to_variable(self, richr_addr: RichR[claripy.ast.BV], size: int):
|
|
673
|
+
def _store_to_variable(self, richr_addr: RichR[claripy.ast.BV], data: RichR, size: int):
|
|
673
674
|
addr_variable = richr_addr.variable
|
|
674
675
|
codeloc = self._codeloc()
|
|
675
676
|
|
|
@@ -691,7 +692,8 @@ class SimEngineVRBase(
|
|
|
691
692
|
store_typevar = self._create_access_typevar(base_typevar, True, size, field_offset)
|
|
692
693
|
if addr_variable is not None:
|
|
693
694
|
self.state.typevars.add_type_variable(addr_variable, codeloc, typevar)
|
|
694
|
-
|
|
695
|
+
data_typevar = data.typevar if data.typevar is not None else typeconsts.TopType()
|
|
696
|
+
self.state.add_type_constraint(typevars.Subtype(store_typevar, data_typevar))
|
|
695
697
|
|
|
696
698
|
def _load(self, richr_addr: RichR[claripy.ast.BV], size: int, expr=None):
|
|
697
699
|
"""
|
|
@@ -941,13 +943,13 @@ class SimEngineVRBase(
|
|
|
941
943
|
# it's an array!
|
|
942
944
|
if offset.concrete:
|
|
943
945
|
concrete_offset = offset.concrete_value * elem_size
|
|
944
|
-
load_typevar = self._create_access_typevar(typevar,
|
|
946
|
+
load_typevar = self._create_access_typevar(typevar, False, size, concrete_offset)
|
|
945
947
|
self.state.add_type_constraint(typevars.Subtype(load_typevar, typeconsts.TopType()))
|
|
946
948
|
else:
|
|
947
949
|
# FIXME: This is a hack
|
|
948
950
|
for i in range(4):
|
|
949
951
|
concrete_offset = size * i
|
|
950
|
-
load_typevar = self._create_access_typevar(typevar,
|
|
952
|
+
load_typevar = self._create_access_typevar(typevar, False, size, concrete_offset)
|
|
951
953
|
self.state.add_type_constraint(typevars.Subtype(load_typevar, typeconsts.TopType()))
|
|
952
954
|
|
|
953
955
|
return RichR(self.state.top(size * self.project.arch.byte_width), typevar=typevar)
|
|
@@ -8,12 +8,13 @@ from archinfo.arch_arm import is_arm_arch
|
|
|
8
8
|
|
|
9
9
|
from angr.block import Block
|
|
10
10
|
from angr.errors import SimMemoryMissingError
|
|
11
|
-
from angr.calling_conventions import SimRegArg, SimStackArg, default_cc
|
|
11
|
+
from angr.calling_conventions import SimRegArg, SimStackArg, SimTypeFunction, default_cc
|
|
12
12
|
from angr.engines.vex.claripy.datalayer import value as claripy_value
|
|
13
13
|
from angr.engines.light import SimEngineNostmtVEX
|
|
14
14
|
from angr.knowledge_plugins import Function
|
|
15
15
|
from angr.storage.memory_mixins.paged_memory.pages.multi_values import MultiValues
|
|
16
16
|
from angr.analyses.typehoon import typevars, typeconsts
|
|
17
|
+
from angr.sim_type import SimTypeBottom
|
|
17
18
|
from .engine_base import SimEngineVRBase, RichR
|
|
18
19
|
from .irsb_scanner import VEXIRSBScanner
|
|
19
20
|
|
|
@@ -222,24 +223,39 @@ class SimEngineVRVEX(
|
|
|
222
223
|
|
|
223
224
|
def _process_block_end(self, stmt_result, whitelist):
|
|
224
225
|
# handles block-end calls
|
|
226
|
+
has_call = False
|
|
225
227
|
current_addr = self.state.block_addr
|
|
226
228
|
for target_func in self.call_info.get(current_addr, []):
|
|
227
229
|
self._handle_function_concrete(target_func)
|
|
230
|
+
has_call = True
|
|
228
231
|
|
|
229
|
-
if self.block.vex.jumpkind == "Ijk_Call":
|
|
232
|
+
if has_call or self.block.vex.jumpkind == "Ijk_Call":
|
|
230
233
|
# emulates return values from calls
|
|
231
234
|
cc = None
|
|
235
|
+
proto: SimTypeFunction | None = None
|
|
232
236
|
for target_func in self.call_info.get(self.state.block_addr, []):
|
|
233
237
|
if target_func.calling_convention is not None:
|
|
234
238
|
cc = target_func.calling_convention
|
|
239
|
+
proto = target_func.prototype
|
|
235
240
|
break
|
|
236
241
|
if cc is None:
|
|
237
242
|
cc = default_cc(self.arch.name, platform=self.project.simos.name)(self.arch)
|
|
238
|
-
|
|
239
|
-
|
|
243
|
+
|
|
244
|
+
if proto is not None and not isinstance(proto.returnty, SimTypeBottom):
|
|
245
|
+
ret_reg = cc.return_val(proto.returnty)
|
|
246
|
+
else:
|
|
247
|
+
ret_reg = cc.RETURN_VAL
|
|
248
|
+
if isinstance(ret_reg, SimRegArg):
|
|
249
|
+
reg_offset, reg_size = self.arch.registers[ret_reg.reg_name]
|
|
240
250
|
data = self._top(reg_size * self.arch.byte_width)
|
|
241
251
|
self._assign_to_register(reg_offset, data, reg_size, create_variable=False)
|
|
242
252
|
|
|
253
|
+
# handle tail-call optimizations
|
|
254
|
+
if self.block.vex.jumpkind == "Ijk_Boring":
|
|
255
|
+
self.state.ret_val_size = (
|
|
256
|
+
reg_size if self.state.ret_val_size is None else max(self.state.ret_val_size, reg_size)
|
|
257
|
+
)
|
|
258
|
+
|
|
243
259
|
elif self.block.vex.jumpkind == "Ijk_Ret":
|
|
244
260
|
# handles return statements
|
|
245
261
|
|
angr/block.py
CHANGED
|
@@ -130,19 +130,23 @@ class Block(Serializable):
|
|
|
130
130
|
BLOCK_MAX_SIZE = 4096
|
|
131
131
|
|
|
132
132
|
__slots__ = [
|
|
133
|
+
"_backup_state",
|
|
133
134
|
"_bytes",
|
|
134
135
|
"_capstone",
|
|
135
136
|
"_collect_data_refs",
|
|
136
137
|
"_const_prop",
|
|
137
138
|
"_cross_insn_opt",
|
|
138
139
|
"_disassembly",
|
|
140
|
+
"_extra_stop_points",
|
|
139
141
|
"_initial_regs",
|
|
140
142
|
"_instruction_addrs",
|
|
141
143
|
"_instructions",
|
|
142
144
|
"_load_from_ro_regions",
|
|
145
|
+
"_max_size",
|
|
143
146
|
"_opt_level",
|
|
144
147
|
"_project",
|
|
145
148
|
"_strict_block_end",
|
|
149
|
+
"_traceflags",
|
|
146
150
|
"_vex",
|
|
147
151
|
"_vex_nostmt",
|
|
148
152
|
"addr",
|
|
@@ -155,11 +159,10 @@ class Block(Serializable):
|
|
|
155
159
|
self,
|
|
156
160
|
addr,
|
|
157
161
|
project=None,
|
|
158
|
-
arch: Arch = None,
|
|
162
|
+
arch: Arch | None = None,
|
|
159
163
|
size=None,
|
|
160
164
|
max_size=None,
|
|
161
165
|
byte_string=None,
|
|
162
|
-
vex=None,
|
|
163
166
|
thumb=False,
|
|
164
167
|
backup_state=None,
|
|
165
168
|
extra_stop_points=None,
|
|
@@ -174,14 +177,11 @@ class Block(Serializable):
|
|
|
174
177
|
initial_regs=None,
|
|
175
178
|
skip_stmts=False,
|
|
176
179
|
):
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
+
if arch is not None:
|
|
181
|
+
self.arch = arch
|
|
182
|
+
elif project is not None:
|
|
180
183
|
self.arch = project.arch
|
|
181
184
|
else:
|
|
182
|
-
self.arch = arch
|
|
183
|
-
|
|
184
|
-
if self.arch is None:
|
|
185
185
|
raise ValueError('Either "project" or "arch" has to be specified.')
|
|
186
186
|
|
|
187
187
|
if project is not None and backup_state is None and project.kb.patches.values():
|
|
@@ -195,63 +195,23 @@ class Block(Serializable):
|
|
|
195
195
|
else:
|
|
196
196
|
thumb = False
|
|
197
197
|
|
|
198
|
-
self._project
|
|
199
|
-
self.thumb = thumb
|
|
198
|
+
self._project = project
|
|
200
199
|
self.addr = addr
|
|
200
|
+
self._backup_state = backup_state
|
|
201
|
+
self.thumb = thumb
|
|
201
202
|
self._opt_level = opt_level
|
|
202
|
-
self._initial_regs
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
self._initial_regs = initial_regs if (collect_data_refs or const_prop) else None
|
|
204
|
+
self._traceflags = traceflags
|
|
205
|
+
self._extra_stop_points = extra_stop_points
|
|
206
|
+
self._max_size = max_size if max_size is not None else self.BLOCK_MAX_SIZE
|
|
205
207
|
|
|
206
208
|
if self._project is None and byte_string is None:
|
|
207
209
|
raise ValueError('"byte_string" has to be specified if "project" is not provided.')
|
|
208
210
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
size = len(byte_string)
|
|
212
|
-
elif vex is not None:
|
|
213
|
-
size = vex.size
|
|
214
|
-
else:
|
|
215
|
-
if self._initial_regs:
|
|
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
|
-
)
|
|
224
|
-
vex = self._vex_engine.lift_vex(
|
|
225
|
-
clemory=clemory,
|
|
226
|
-
state=backup_state,
|
|
227
|
-
insn_bytes=byte_string,
|
|
228
|
-
addr=addr,
|
|
229
|
-
size=max_size,
|
|
230
|
-
thumb=thumb,
|
|
231
|
-
extra_stop_points=extra_stop_points,
|
|
232
|
-
opt_level=opt_level,
|
|
233
|
-
num_inst=num_inst,
|
|
234
|
-
traceflags=traceflags,
|
|
235
|
-
strict_block_end=strict_block_end,
|
|
236
|
-
collect_data_refs=collect_data_refs,
|
|
237
|
-
load_from_ro_regions=load_from_ro_regions,
|
|
238
|
-
const_prop=const_prop,
|
|
239
|
-
cross_insn_opt=cross_insn_opt,
|
|
240
|
-
skip_stmts=skip_stmts,
|
|
241
|
-
)
|
|
242
|
-
if self._initial_regs:
|
|
243
|
-
self.reset_initial_regs()
|
|
244
|
-
size = vex.size
|
|
245
|
-
|
|
246
|
-
if skip_stmts:
|
|
247
|
-
self._vex = None
|
|
248
|
-
self._vex_nostmt = vex
|
|
249
|
-
else:
|
|
250
|
-
self._vex = vex
|
|
251
|
-
self._vex_nostmt = None
|
|
211
|
+
self._vex = None
|
|
212
|
+
self._vex_nostmt = None
|
|
252
213
|
self._disassembly = None
|
|
253
214
|
self._capstone = None
|
|
254
|
-
self.size = size
|
|
255
215
|
self._collect_data_refs = collect_data_refs
|
|
256
216
|
self._strict_block_end = strict_block_end
|
|
257
217
|
self._cross_insn_opt = cross_insn_opt
|
|
@@ -261,6 +221,23 @@ class Block(Serializable):
|
|
|
261
221
|
self._instructions: int | None = num_inst
|
|
262
222
|
self._instruction_addrs: list[int] = []
|
|
263
223
|
|
|
224
|
+
self._bytes = byte_string
|
|
225
|
+
self.size = size
|
|
226
|
+
|
|
227
|
+
if size is None:
|
|
228
|
+
if byte_string is not None:
|
|
229
|
+
size = len(byte_string)
|
|
230
|
+
else:
|
|
231
|
+
vex = self._lift_nocache(skip_stmts)
|
|
232
|
+
size = vex.size
|
|
233
|
+
|
|
234
|
+
if skip_stmts:
|
|
235
|
+
self._vex_nostmt = vex
|
|
236
|
+
else:
|
|
237
|
+
self._vex = vex
|
|
238
|
+
|
|
239
|
+
self.size = size
|
|
240
|
+
|
|
264
241
|
if skip_stmts:
|
|
265
242
|
self._parse_vex_info(self._vex_nostmt)
|
|
266
243
|
else:
|
|
@@ -343,50 +320,7 @@ class Block(Serializable):
|
|
|
343
320
|
raise ValueError("Project is not set")
|
|
344
321
|
return self._project.factory.default_engine # type:ignore
|
|
345
322
|
|
|
346
|
-
|
|
347
|
-
def vex(self) -> IRSB | PcodeIRSB:
|
|
348
|
-
if not self._vex:
|
|
349
|
-
if self._initial_regs:
|
|
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
|
-
)
|
|
358
|
-
self._vex = self._vex_engine.lift_vex(
|
|
359
|
-
clemory=clemory,
|
|
360
|
-
insn_bytes=self._bytes,
|
|
361
|
-
addr=self.addr,
|
|
362
|
-
thumb=self.thumb,
|
|
363
|
-
size=self.size,
|
|
364
|
-
num_inst=self._instructions,
|
|
365
|
-
opt_level=self._opt_level,
|
|
366
|
-
arch=self.arch,
|
|
367
|
-
collect_data_refs=self._collect_data_refs,
|
|
368
|
-
strict_block_end=self._strict_block_end,
|
|
369
|
-
cross_insn_opt=self._cross_insn_opt,
|
|
370
|
-
load_from_ro_regions=self._load_from_ro_regions,
|
|
371
|
-
const_prop=self._const_prop,
|
|
372
|
-
)
|
|
373
|
-
if self._initial_regs:
|
|
374
|
-
self.reset_initial_regs()
|
|
375
|
-
self._parse_vex_info(self._vex)
|
|
376
|
-
|
|
377
|
-
assert self._vex is not None
|
|
378
|
-
return self._vex
|
|
379
|
-
|
|
380
|
-
@property
|
|
381
|
-
def vex_nostmt(self):
|
|
382
|
-
if self._vex_nostmt:
|
|
383
|
-
return self._vex_nostmt
|
|
384
|
-
|
|
385
|
-
if self._vex:
|
|
386
|
-
return self._vex
|
|
387
|
-
|
|
388
|
-
if self._initial_regs:
|
|
389
|
-
self.set_initial_regs()
|
|
323
|
+
def _lift_nocache(self, skip_stmts: bool) -> IRSB | PcodeIRSB:
|
|
390
324
|
clemory = None
|
|
391
325
|
if self._project is not None:
|
|
392
326
|
clemory = (
|
|
@@ -394,25 +328,53 @@ class Block(Serializable):
|
|
|
394
328
|
if self._project.loader.memory_ro_view is not None
|
|
395
329
|
else self._project.loader.memory
|
|
396
330
|
)
|
|
397
|
-
|
|
331
|
+
|
|
332
|
+
if self._initial_regs:
|
|
333
|
+
self.set_initial_regs()
|
|
334
|
+
|
|
335
|
+
vex = self._vex_engine.lift_vex(
|
|
336
|
+
addr=self.addr,
|
|
337
|
+
state=self._backup_state,
|
|
398
338
|
clemory=clemory,
|
|
399
339
|
insn_bytes=self._bytes,
|
|
400
|
-
|
|
401
|
-
thumb=self.thumb,
|
|
340
|
+
arch=self.arch,
|
|
402
341
|
size=self.size,
|
|
403
342
|
num_inst=self._instructions,
|
|
343
|
+
traceflags=self._traceflags,
|
|
344
|
+
thumb=self.thumb,
|
|
345
|
+
extra_stop_points=self._extra_stop_points,
|
|
404
346
|
opt_level=self._opt_level,
|
|
405
|
-
arch=self.arch,
|
|
406
|
-
skip_stmts=True,
|
|
407
|
-
collect_data_refs=self._collect_data_refs,
|
|
408
347
|
strict_block_end=self._strict_block_end,
|
|
348
|
+
skip_stmts=skip_stmts,
|
|
349
|
+
collect_data_refs=self._collect_data_refs,
|
|
409
350
|
cross_insn_opt=self._cross_insn_opt,
|
|
410
351
|
load_from_ro_regions=self._load_from_ro_regions,
|
|
411
352
|
const_prop=self._const_prop,
|
|
412
353
|
)
|
|
354
|
+
|
|
413
355
|
if self._initial_regs:
|
|
414
356
|
self.reset_initial_regs()
|
|
357
|
+
|
|
358
|
+
return vex
|
|
359
|
+
|
|
360
|
+
@property
|
|
361
|
+
def vex(self) -> IRSB | PcodeIRSB:
|
|
362
|
+
if not self._vex:
|
|
363
|
+
self._vex = self._lift_nocache(False)
|
|
364
|
+
self._parse_vex_info(self._vex)
|
|
365
|
+
|
|
366
|
+
return self._vex
|
|
367
|
+
|
|
368
|
+
@property
|
|
369
|
+
def vex_nostmt(self):
|
|
370
|
+
if self._vex_nostmt:
|
|
371
|
+
return self._vex_nostmt
|
|
372
|
+
if self._vex:
|
|
373
|
+
return self._vex
|
|
374
|
+
|
|
375
|
+
self._vex_nostmt = self._lift_nocache(True)
|
|
415
376
|
self._parse_vex_info(self._vex_nostmt)
|
|
377
|
+
|
|
416
378
|
return self._vex_nostmt
|
|
417
379
|
|
|
418
380
|
@property
|
angr/callable.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import pycparser
|
|
3
3
|
|
|
4
|
+
from .sim_manager import SimulationManager
|
|
4
5
|
from .errors import AngrCallableError, AngrCallableMultistateError
|
|
5
6
|
from .calling_conventions import default_cc, SimCC
|
|
6
7
|
|
|
@@ -28,6 +29,7 @@ class Callable:
|
|
|
28
29
|
cc=None,
|
|
29
30
|
add_options=None,
|
|
30
31
|
remove_options=None,
|
|
32
|
+
step_limit: int | None = None,
|
|
31
33
|
):
|
|
32
34
|
"""
|
|
33
35
|
:param project: The project to operate on
|
|
@@ -60,6 +62,7 @@ class Callable:
|
|
|
60
62
|
self._func_ty = prototype
|
|
61
63
|
self._add_options = add_options if add_options else set()
|
|
62
64
|
self._remove_options = remove_options if remove_options else set()
|
|
65
|
+
self._step_limit = step_limit
|
|
63
66
|
|
|
64
67
|
self.result_path_group = None
|
|
65
68
|
self.result_state = None
|
|
@@ -95,16 +98,12 @@ class Callable:
|
|
|
95
98
|
remove_options=self._remove_options,
|
|
96
99
|
)
|
|
97
100
|
|
|
98
|
-
def step_func(pg):
|
|
99
|
-
pg2 = pg.prune()
|
|
100
|
-
if len(pg2.active) > 1:
|
|
101
|
-
raise AngrCallableMultistateError("Execution split on symbolic condition!")
|
|
102
|
-
return pg2
|
|
103
|
-
|
|
104
101
|
caller = self._project.factory.simulation_manager(state)
|
|
105
|
-
caller.run(step_func=
|
|
102
|
+
caller.run(step_func=self._step_func).unstash(from_stash="deadended")
|
|
106
103
|
caller.prune(filter_func=lambda pt: pt.addr == self._deadend_addr)
|
|
107
104
|
|
|
105
|
+
if "step_limited" in caller.stashes:
|
|
106
|
+
caller.stash(from_stash="step_limited", to_stash="active")
|
|
108
107
|
if len(caller.active) == 0:
|
|
109
108
|
raise AngrCallableError("No paths returned from function")
|
|
110
109
|
|
|
@@ -159,3 +158,11 @@ class Callable:
|
|
|
159
158
|
raise AngrCallableError(f"Unsupported expression type {type(expr)}.")
|
|
160
159
|
|
|
161
160
|
return self.__call__(*args)
|
|
161
|
+
|
|
162
|
+
def _step_func(self, pg: SimulationManager):
|
|
163
|
+
pg2 = pg.prune()
|
|
164
|
+
if self._concrete_only and len(pg2.active) > 1:
|
|
165
|
+
raise AngrCallableMultistateError("Execution split on symbolic condition!")
|
|
166
|
+
if self._step_limit:
|
|
167
|
+
pg2.stash(filter_func=lambda p: p.history.depth >= self._step_limit, to_stash="step_limited")
|
|
168
|
+
return pg2
|