angr 9.2.123__py3-none-manylinux2014_x86_64.whl → 9.2.124__py3-none-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +11 -8
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_got.py +2 -2
- angr/analyses/decompiler/ail_simplifier.py +16 -19
- angr/analyses/decompiler/callsite_maker.py +8 -7
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +24 -2
- angr/analyses/decompiler/clinic.py +27 -1
- angr/analyses/decompiler/condition_processor.py +10 -3
- angr/analyses/decompiler/decompilation_cache.py +2 -0
- angr/analyses/decompiler/decompiler.py +50 -8
- angr/analyses/decompiler/dephication/graph_vvar_mapping.py +10 -2
- angr/analyses/decompiler/dephication/rewriting_engine.py +64 -1
- angr/analyses/decompiler/expression_narrower.py +5 -1
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +4 -1
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +7 -0
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +23 -4
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +3 -1
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +8 -5
- angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +10 -5
- angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +18 -7
- angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +6 -0
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +2 -0
- angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +2 -0
- angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +8 -2
- angr/analyses/decompiler/region_identifier.py +36 -0
- angr/analyses/decompiler/region_simplifiers/loop.py +2 -8
- angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +9 -3
- angr/analyses/decompiler/ssailification/rewriting.py +5 -2
- angr/analyses/decompiler/ssailification/rewriting_engine.py +151 -25
- angr/analyses/decompiler/ssailification/rewriting_state.py +1 -0
- angr/analyses/decompiler/ssailification/ssailification.py +17 -9
- angr/analyses/decompiler/ssailification/traversal.py +3 -1
- angr/analyses/decompiler/ssailification/traversal_engine.py +35 -8
- angr/analyses/decompiler/ssailification/traversal_state.py +1 -0
- angr/analyses/decompiler/structured_codegen/c.py +42 -4
- angr/analyses/decompiler/structuring/phoenix.py +3 -0
- angr/analyses/propagator/engine_ail.py +10 -3
- angr/analyses/reaching_definitions/engine_ail.py +10 -15
- angr/analyses/s_propagator.py +16 -9
- angr/analyses/s_reaching_definitions/s_rda_view.py +127 -63
- angr/analyses/variable_recovery/engine_ail.py +14 -0
- angr/analyses/variable_recovery/engine_base.py +11 -0
- angr/engines/light/engine.py +12 -0
- angr/knowledge_plugins/__init__.py +2 -0
- angr/knowledge_plugins/decompilation.py +45 -0
- angr/knowledge_plugins/key_definitions/atoms.py +8 -0
- angr/procedures/definitions/parse_win32json.py +2 -1
- angr/storage/memory_mixins/actions_mixin.py +7 -7
- angr/storage/memory_mixins/address_concretization_mixin.py +5 -5
- angr/storage/memory_mixins/bvv_conversion_mixin.py +1 -1
- angr/storage/memory_mixins/clouseau_mixin.py +3 -3
- angr/storage/memory_mixins/conditional_store_mixin.py +3 -3
- angr/storage/memory_mixins/default_filler_mixin.py +3 -3
- angr/storage/memory_mixins/memory_mixin.py +45 -34
- angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +15 -14
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +27 -16
- angr/storage/memory_mixins/paged_memory/pages/cooperation.py +18 -9
- angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +5 -5
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +89 -55
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +16 -25
- angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +11 -9
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +23 -7
- angr/storage/memory_mixins/paged_memory/privileged_mixin.py +1 -1
- angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +9 -7
- angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +9 -9
- angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +1 -0
- angr/storage/memory_mixins/simple_interface_mixin.py +2 -2
- angr/storage/memory_mixins/simplification_mixin.py +2 -2
- angr/storage/memory_mixins/size_resolution_mixin.py +1 -1
- angr/storage/memory_mixins/slotted_memory.py +3 -3
- angr/storage/memory_mixins/smart_find_mixin.py +1 -0
- angr/storage/memory_mixins/underconstrained_mixin.py +5 -5
- angr/storage/memory_mixins/unwrapper_mixin.py +4 -4
- angr/storage/memory_object.py +4 -3
- angr/utils/constants.py +1 -1
- angr/utils/graph.py +15 -0
- angr/vaults.py +2 -2
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/METADATA +6 -6
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/RECORD +83 -82
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/WHEEL +1 -1
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/LICENSE +0 -0
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/entry_points.txt +0 -0
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/top_level.txt +0 -0
|
@@ -740,9 +740,16 @@ class SimEnginePropagatorAIL(
|
|
|
740
740
|
return PropValue.from_value_and_details(v, expr.size, expr, self._codeloc())
|
|
741
741
|
|
|
742
742
|
def _ail_handle_DirtyExpression(self, expr: Expr.DirtyExpression) -> PropValue | None: # pylint:disable=no-self-use
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
743
|
+
for operand in expr.operands:
|
|
744
|
+
_ = self._expr(operand)
|
|
745
|
+
|
|
746
|
+
return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
|
|
747
|
+
|
|
748
|
+
def _ail_handle_VEXCCallExpression(
|
|
749
|
+
self, expr: Expr.VEXCCallExpression
|
|
750
|
+
) -> PropValue | None: # pylint:disable=no-self-use
|
|
751
|
+
for operand in expr.operands:
|
|
752
|
+
_ = self._expr(operand)
|
|
746
753
|
|
|
747
754
|
return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
|
|
748
755
|
|
|
@@ -7,7 +7,6 @@ import logging
|
|
|
7
7
|
import archinfo
|
|
8
8
|
import claripy
|
|
9
9
|
import ailment
|
|
10
|
-
import pyvex
|
|
11
10
|
from claripy import FSORT_DOUBLE, FSORT_FLOAT
|
|
12
11
|
|
|
13
12
|
from angr.engines.light import SimEngineLight, SimEngineLightAILMixin, SpOffset
|
|
@@ -364,17 +363,7 @@ class SimEngineRDAIL(
|
|
|
364
363
|
# self.state.add_use(Register(self.project.arch.sp_offset, self.project.arch.bits // 8))
|
|
365
364
|
|
|
366
365
|
def _ail_handle_DirtyStatement(self, stmt: ailment.Stmt.DirtyStatement):
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
if isinstance(stmt.dirty_stmt, pyvex.stmt.Dirty):
|
|
370
|
-
# TODO: We need dirty helpers for a more complete understanding of clobbered registers
|
|
371
|
-
tmp = stmt.dirty_stmt.tmp
|
|
372
|
-
if tmp in (-1, 0xFFFFFFFF):
|
|
373
|
-
return
|
|
374
|
-
size = 32 # FIXME: We don't know the size.
|
|
375
|
-
self.state.kill_and_add_definition(Tmp(tmp, size), MultiValues(self.state.top(size)))
|
|
376
|
-
else:
|
|
377
|
-
l.warning("Unexpected type of dirty statement %s.", type(stmt.dirty_stmt))
|
|
366
|
+
self._expr(stmt.dirty)
|
|
378
367
|
|
|
379
368
|
#
|
|
380
369
|
# AIL expression handlers
|
|
@@ -1125,12 +1114,18 @@ class SimEngineRDAIL(
|
|
|
1125
1114
|
stack_addr = self.state.stack_address(expr.offset)
|
|
1126
1115
|
return MultiValues(stack_addr)
|
|
1127
1116
|
|
|
1117
|
+
def _ail_handle_VEXCCallExpression(self, expr: ailment.Expr.VEXCCallExpression) -> MultiValues:
|
|
1118
|
+
for operand in expr.operands:
|
|
1119
|
+
self._expr(operand)
|
|
1120
|
+
|
|
1121
|
+
top = self.state.top(expr.bits)
|
|
1122
|
+
return MultiValues(top)
|
|
1123
|
+
|
|
1128
1124
|
def _ail_handle_DirtyExpression(
|
|
1129
1125
|
self, expr: ailment.Expr.DirtyExpression
|
|
1130
1126
|
) -> MultiValues: # pylint:disable=no-self-use
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
self._expr(operand)
|
|
1127
|
+
for operand in expr.operands:
|
|
1128
|
+
self._expr(operand)
|
|
1134
1129
|
|
|
1135
1130
|
top = self.state.top(expr.bits)
|
|
1136
1131
|
return MultiValues(top)
|
angr/analyses/s_propagator.py
CHANGED
|
@@ -238,15 +238,22 @@ class SPropagatorAnalysis(Analysis):
|
|
|
238
238
|
|
|
239
239
|
if len(tmp_uses) <= 2:
|
|
240
240
|
tmp_used, tmp_use_stmtidx = next(iter(tmp_uses))
|
|
241
|
-
if is_const_vvar_load_dirty_assignment(stmt)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
241
|
+
if is_const_vvar_load_dirty_assignment(stmt):
|
|
242
|
+
same_inst = (
|
|
243
|
+
block.statements[tmp_def_stmtidx].ins_addr == block.statements[tmp_use_stmtidx].ins_addr
|
|
244
|
+
)
|
|
245
|
+
has_store = any(
|
|
246
|
+
isinstance(stmt_, Store)
|
|
247
|
+
for stmt_ in block.statements[tmp_def_stmtidx + 1 : tmp_use_stmtidx]
|
|
248
|
+
)
|
|
249
|
+
if same_inst or not has_store:
|
|
250
|
+
# we can propagate this load because either we do not consider memory aliasing problem
|
|
251
|
+
# within the same instruction (blocks must be originally lifted with
|
|
252
|
+
# CROSS_INSN_OPT=False), or there is no store between its def and use.
|
|
253
|
+
replacements[
|
|
254
|
+
CodeLocation(block_loc.block_addr, tmp_use_stmtidx, block_idx=block_loc.block_idx)
|
|
255
|
+
][tmp_used] = stmt.src
|
|
256
|
+
continue
|
|
250
257
|
|
|
251
258
|
self.model.replacements = replacements
|
|
252
259
|
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
from collections import defaultdict
|
|
5
5
|
|
|
6
|
-
from ailment.statement import Assignment, Call, Label
|
|
6
|
+
from ailment.statement import Statement, Assignment, Call, Label
|
|
7
7
|
from ailment.expression import VirtualVariable, Expression
|
|
8
8
|
|
|
9
9
|
from angr.utils.ail import is_phi_assignment
|
|
@@ -17,27 +17,141 @@ from .s_rda_model import SRDAModel
|
|
|
17
17
|
log = logging.getLogger(__name__)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
class
|
|
20
|
+
class RegVVarPredicate:
|
|
21
21
|
"""
|
|
22
|
-
|
|
22
|
+
Implements a predicate that is used in get_reg_vvar_by_stmt_idx and get_reg_vvar_by_insn.
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
|
-
def __init__(self,
|
|
26
|
-
self.
|
|
25
|
+
def __init__(self, reg_offset: int, vvars: set[VirtualVariable], arch):
|
|
26
|
+
self.reg_offset = reg_offset
|
|
27
|
+
self.vvars = vvars
|
|
28
|
+
self.arch = arch
|
|
27
29
|
|
|
28
30
|
def _get_call_clobbered_regs(self, stmt: Call) -> set[int]:
|
|
29
31
|
cc = stmt.calling_convention
|
|
30
32
|
if cc is None:
|
|
31
33
|
# get the default calling convention
|
|
32
|
-
cc = default_cc(self.
|
|
34
|
+
cc = default_cc(self.arch.name) # TODO: platform and language
|
|
33
35
|
if cc is not None:
|
|
34
36
|
reg_list = cc.CALLER_SAVED_REGS
|
|
35
37
|
if isinstance(cc.RETURN_VAL, SimRegArg):
|
|
36
38
|
reg_list.append(cc.RETURN_VAL.reg_name)
|
|
37
|
-
return {self.
|
|
39
|
+
return {self.arch.registers[reg_name][0] for reg_name in reg_list}
|
|
38
40
|
log.warning("Cannot determine registers that are clobbered by call statement %r.", stmt)
|
|
39
41
|
return set()
|
|
40
42
|
|
|
43
|
+
def predicate(self, stmt: Statement) -> bool:
|
|
44
|
+
if (
|
|
45
|
+
isinstance(stmt, Assignment)
|
|
46
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
47
|
+
and stmt.dst.was_reg
|
|
48
|
+
and stmt.dst.reg_offset == self.reg_offset
|
|
49
|
+
):
|
|
50
|
+
self.vvars.add(stmt.dst)
|
|
51
|
+
return True
|
|
52
|
+
if isinstance(stmt, Call):
|
|
53
|
+
if (
|
|
54
|
+
isinstance(stmt.ret_expr, VirtualVariable)
|
|
55
|
+
and stmt.ret_expr.was_reg
|
|
56
|
+
and stmt.ret_expr.reg_offset == self.reg_offset
|
|
57
|
+
):
|
|
58
|
+
self.vvars.add(stmt.ret_expr)
|
|
59
|
+
return True
|
|
60
|
+
# is it clobbered maybe?
|
|
61
|
+
clobbered_regs = self._get_call_clobbered_regs(stmt)
|
|
62
|
+
if self.reg_offset in clobbered_regs:
|
|
63
|
+
return True
|
|
64
|
+
return False
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class StackVVarPredicate:
|
|
68
|
+
"""
|
|
69
|
+
Implements a predicate that is used in get_stack_vvar_by_stmt_idx and get_stack_vvar_by_insn.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(self, stack_offset: int, size: int, vvars: set[VirtualVariable]):
|
|
73
|
+
self.stack_offset = stack_offset
|
|
74
|
+
self.size = size
|
|
75
|
+
self.vvars = vvars
|
|
76
|
+
|
|
77
|
+
def predicate(self, stmt: Statement) -> bool:
|
|
78
|
+
if (
|
|
79
|
+
isinstance(stmt, Assignment)
|
|
80
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
81
|
+
and stmt.dst.was_stack
|
|
82
|
+
and stmt.dst.stack_offset == self.stack_offset
|
|
83
|
+
and stmt.dst.size == self.size
|
|
84
|
+
):
|
|
85
|
+
self.vvars.add(stmt.dst)
|
|
86
|
+
return True
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class SRDAView:
|
|
91
|
+
"""
|
|
92
|
+
A view of SRDA model that provides various functionalities for querying the model.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
def __init__(self, model: SRDAModel):
|
|
96
|
+
self.model = model
|
|
97
|
+
|
|
98
|
+
def _get_vvar_by_stmt(
|
|
99
|
+
self, block_addr: int, block_idx: int | None, stmt_idx: int, op_type: ObservationPointType, predicate
|
|
100
|
+
):
|
|
101
|
+
# find the starting block
|
|
102
|
+
for block in self.model.func_graph:
|
|
103
|
+
if block.addr == block_addr and block.idx == block_idx:
|
|
104
|
+
the_block = block
|
|
105
|
+
break
|
|
106
|
+
else:
|
|
107
|
+
return
|
|
108
|
+
|
|
109
|
+
traversed = set()
|
|
110
|
+
queue = [(the_block, stmt_idx if op_type == ObservationPointType.OP_BEFORE else stmt_idx + 1)]
|
|
111
|
+
while queue:
|
|
112
|
+
block, start_stmt_idx = queue.pop(0)
|
|
113
|
+
traversed.add(block)
|
|
114
|
+
|
|
115
|
+
stmts = block.statements[:start_stmt_idx] if start_stmt_idx is not None else block.statements
|
|
116
|
+
|
|
117
|
+
for stmt in reversed(stmts):
|
|
118
|
+
should_break = predicate(stmt)
|
|
119
|
+
if should_break:
|
|
120
|
+
break
|
|
121
|
+
else:
|
|
122
|
+
# not found
|
|
123
|
+
for pred in self.model.func_graph.predecessors(block):
|
|
124
|
+
if pred not in traversed:
|
|
125
|
+
traversed.add(pred)
|
|
126
|
+
queue.append((pred, None))
|
|
127
|
+
|
|
128
|
+
def get_reg_vvar_by_stmt(
|
|
129
|
+
self, reg_offset: int, block_addr: int, block_idx: int | None, stmt_idx: int, op_type: ObservationPointType
|
|
130
|
+
) -> VirtualVariable | None:
|
|
131
|
+
reg_offset = get_reg_offset_base(reg_offset, self.model.arch)
|
|
132
|
+
vvars = set()
|
|
133
|
+
predicater = RegVVarPredicate(reg_offset, vvars, self.model.arch)
|
|
134
|
+
self._get_vvar_by_stmt(block_addr, block_idx, stmt_idx, op_type, predicater.predicate)
|
|
135
|
+
|
|
136
|
+
assert len(vvars) <= 1
|
|
137
|
+
return next(iter(vvars), None)
|
|
138
|
+
|
|
139
|
+
def get_stack_vvar_by_stmt( # pylint: disable=too-many-positional-arguments
|
|
140
|
+
self,
|
|
141
|
+
stack_offset: int,
|
|
142
|
+
size: int,
|
|
143
|
+
block_addr: int,
|
|
144
|
+
block_idx: int | None,
|
|
145
|
+
stmt_idx: int,
|
|
146
|
+
op_type: ObservationPointType,
|
|
147
|
+
) -> VirtualVariable | None:
|
|
148
|
+
vvars = set()
|
|
149
|
+
predicater = StackVVarPredicate(stack_offset, size, vvars)
|
|
150
|
+
self._get_vvar_by_stmt(block_addr, block_idx, stmt_idx, op_type, predicater.predicate)
|
|
151
|
+
|
|
152
|
+
assert len(vvars) <= 1
|
|
153
|
+
return next(iter(vvars), None)
|
|
154
|
+
|
|
41
155
|
def _get_vvar_by_insn(self, addr: int, op_type: ObservationPointType, predicate, block_idx: int | None = None):
|
|
42
156
|
# find the starting block
|
|
43
157
|
for block in self.model.func_graph:
|
|
@@ -47,6 +161,7 @@ class SRDAView:
|
|
|
47
161
|
else:
|
|
48
162
|
return
|
|
49
163
|
|
|
164
|
+
# determine the starting stmt_idx
|
|
50
165
|
starting_stmt_idx = len(the_block.statements) if op_type == ObservationPointType.OP_AFTER else 0
|
|
51
166
|
for stmt_idx, stmt in enumerate(the_block.statements):
|
|
52
167
|
# skip all labels and phi assignments
|
|
@@ -65,55 +180,16 @@ class SRDAView:
|
|
|
65
180
|
starting_stmt_idx = stmt_idx
|
|
66
181
|
break
|
|
67
182
|
|
|
68
|
-
|
|
69
|
-
queue = [(the_block, starting_stmt_idx)]
|
|
70
|
-
while queue:
|
|
71
|
-
block, start_stmt_idx = queue.pop(0)
|
|
72
|
-
traversed.add(block)
|
|
73
|
-
|
|
74
|
-
stmts = block.statements[:start_stmt_idx] if start_stmt_idx is not None else block.statements
|
|
75
|
-
|
|
76
|
-
for stmt in reversed(stmts):
|
|
77
|
-
should_break = predicate(stmt)
|
|
78
|
-
if should_break:
|
|
79
|
-
break
|
|
80
|
-
else:
|
|
81
|
-
# not found
|
|
82
|
-
for pred in self.model.func_graph.predecessors(block):
|
|
83
|
-
if pred not in traversed:
|
|
84
|
-
traversed.add(pred)
|
|
85
|
-
queue.append((pred, None))
|
|
183
|
+
self._get_vvar_by_stmt(the_block.addr, the_block.idx, starting_stmt_idx, op_type, predicate)
|
|
86
184
|
|
|
87
185
|
def get_reg_vvar_by_insn(
|
|
88
186
|
self, reg_offset: int, addr: int, op_type: ObservationPointType, block_idx: int | None = None
|
|
89
187
|
) -> VirtualVariable | None:
|
|
90
188
|
reg_offset = get_reg_offset_base(reg_offset, self.model.arch)
|
|
91
189
|
vvars = set()
|
|
190
|
+
predicater = RegVVarPredicate(reg_offset, vvars, self.model.arch)
|
|
92
191
|
|
|
93
|
-
|
|
94
|
-
if (
|
|
95
|
-
isinstance(stmt, Assignment)
|
|
96
|
-
and isinstance(stmt.dst, VirtualVariable)
|
|
97
|
-
and stmt.dst.was_reg
|
|
98
|
-
and stmt.dst.reg_offset == reg_offset
|
|
99
|
-
):
|
|
100
|
-
vvars.add(stmt.dst)
|
|
101
|
-
return True
|
|
102
|
-
if isinstance(stmt, Call):
|
|
103
|
-
if (
|
|
104
|
-
isinstance(stmt.ret_expr, VirtualVariable)
|
|
105
|
-
and stmt.ret_expr.was_reg
|
|
106
|
-
and stmt.ret_expr.reg_offset == reg_offset
|
|
107
|
-
):
|
|
108
|
-
vvars.add(stmt.ret_expr)
|
|
109
|
-
return True
|
|
110
|
-
# is it clobbered maybe?
|
|
111
|
-
clobbered_regs = self._get_call_clobbered_regs(stmt)
|
|
112
|
-
if reg_offset in clobbered_regs:
|
|
113
|
-
return True
|
|
114
|
-
return False
|
|
115
|
-
|
|
116
|
-
self._get_vvar_by_insn(addr, op_type, _predicate, block_idx=block_idx)
|
|
192
|
+
self._get_vvar_by_insn(addr, op_type, predicater.predicate, block_idx=block_idx)
|
|
117
193
|
|
|
118
194
|
assert len(vvars) <= 1
|
|
119
195
|
return next(iter(vvars), None)
|
|
@@ -122,20 +198,8 @@ class SRDAView:
|
|
|
122
198
|
self, stack_offset: int, size: int, addr: int, op_type: ObservationPointType, block_idx: int | None = None
|
|
123
199
|
) -> VirtualVariable | None:
|
|
124
200
|
vvars = set()
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
isinstance(stmt, Assignment)
|
|
129
|
-
and isinstance(stmt.dst, VirtualVariable)
|
|
130
|
-
and stmt.dst.was_stack
|
|
131
|
-
and stmt.dst.stack_offset == stack_offset
|
|
132
|
-
and stmt.dst.size == size
|
|
133
|
-
):
|
|
134
|
-
vvars.add(stmt.dst)
|
|
135
|
-
return True
|
|
136
|
-
return False
|
|
137
|
-
|
|
138
|
-
self._get_vvar_by_insn(addr, op_type, _predicate, block_idx=block_idx)
|
|
201
|
+
predicater = StackVVarPredicate(stack_offset, size, vvars)
|
|
202
|
+
self._get_vvar_by_insn(addr, op_type, predicater.predicate, block_idx=block_idx)
|
|
139
203
|
|
|
140
204
|
assert len(vvars) <= 1
|
|
141
205
|
return next(iter(vvars), None)
|
|
@@ -223,6 +223,20 @@ class SimEngineVRAIL(
|
|
|
223
223
|
for ret_expr in stmt.ret_exprs:
|
|
224
224
|
self._expr(ret_expr)
|
|
225
225
|
|
|
226
|
+
def _ail_handle_DirtyExpression(self, expr: ailment.Expr.DirtyExpression) -> RichR:
|
|
227
|
+
for op in expr.operands:
|
|
228
|
+
self._expr(op)
|
|
229
|
+
if expr.guard:
|
|
230
|
+
self._expr(expr.guard)
|
|
231
|
+
if expr.maddr:
|
|
232
|
+
self._expr(expr.maddr)
|
|
233
|
+
return RichR(self.state.top(expr.bits))
|
|
234
|
+
|
|
235
|
+
def _ail_handle_VEXCCallExpression(self, expr: ailment.Expr.VEXCCallExpression) -> RichR:
|
|
236
|
+
for op in expr.operands:
|
|
237
|
+
self._expr(op)
|
|
238
|
+
return RichR(self.state.top(expr.bits))
|
|
239
|
+
|
|
226
240
|
# Expression handlers
|
|
227
241
|
|
|
228
242
|
def _expr(self, expr: ailment.Expr.Expression):
|
|
@@ -435,6 +435,14 @@ class SimEngineVRBase(SimEngineLight):
|
|
|
435
435
|
region=self.func_addr,
|
|
436
436
|
)
|
|
437
437
|
self.variable_manager[self.func_addr].add_variable("register", vvar.oident, variable)
|
|
438
|
+
elif vvar.was_tmp:
|
|
439
|
+
# FIXME: we treat all tmp vvars as registers
|
|
440
|
+
variable = SimRegisterVariable(
|
|
441
|
+
4096 + vvar.tmp_idx,
|
|
442
|
+
vvar.size,
|
|
443
|
+
ident=self.variable_manager[self.func_addr].next_variable_ident("register"),
|
|
444
|
+
region=self.func_addr,
|
|
445
|
+
)
|
|
438
446
|
else:
|
|
439
447
|
raise NotImplementedError
|
|
440
448
|
else:
|
|
@@ -1071,6 +1079,9 @@ class SimEngineVRBase(SimEngineLight):
|
|
|
1071
1079
|
self.variable_manager[self.func_addr].add_variable("stack", vvar.stack_offset, variable)
|
|
1072
1080
|
elif vvar.category == ailment.Expr.VirtualVariableCategory.PARAMETER:
|
|
1073
1081
|
raise KeyError(f"Missing virtual variable for parameter {vvar}")
|
|
1082
|
+
elif vvar.category == ailment.Expr.VirtualVariableCategory.TMP:
|
|
1083
|
+
# we don't track variables for tmps
|
|
1084
|
+
pass
|
|
1074
1085
|
else:
|
|
1075
1086
|
raise NotImplementedError
|
|
1076
1087
|
|
angr/engines/light/engine.py
CHANGED
|
@@ -957,6 +957,9 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
|
|
|
957
957
|
def _ail_handle_Return(self, stmt):
|
|
958
958
|
pass
|
|
959
959
|
|
|
960
|
+
def _ail_handle_DirtyStatement(self, stmt):
|
|
961
|
+
self._expr(stmt.dirty)
|
|
962
|
+
|
|
960
963
|
#
|
|
961
964
|
# Expression handlers
|
|
962
965
|
#
|
|
@@ -1009,6 +1012,15 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
|
|
|
1009
1012
|
|
|
1010
1013
|
return expr
|
|
1011
1014
|
|
|
1015
|
+
def _ail_handle_DirtyExpression(self, expr: ailment.Expr.DirtyExpression):
|
|
1016
|
+
for operand in expr.operands:
|
|
1017
|
+
self._expr(operand)
|
|
1018
|
+
if expr.guard is not None:
|
|
1019
|
+
self._expr(expr.guard)
|
|
1020
|
+
if expr.maddr is not None:
|
|
1021
|
+
self._expr(expr.maddr)
|
|
1022
|
+
return expr
|
|
1023
|
+
|
|
1012
1024
|
def _ail_handle_UnaryOp(self, expr):
|
|
1013
1025
|
handler_name = f"_handle_{expr.op}"
|
|
1014
1026
|
try:
|
|
@@ -17,6 +17,7 @@ from .structured_code import StructuredCodeManager
|
|
|
17
17
|
from .types import TypesStore
|
|
18
18
|
from .callsite_prototypes import CallsitePrototypes
|
|
19
19
|
from .custom_strings import CustomStrings
|
|
20
|
+
from .decompilation import DecompilationManager
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
__all__ = (
|
|
@@ -38,4 +39,5 @@ __all__ = (
|
|
|
38
39
|
"TypesStore",
|
|
39
40
|
"CallsitePrototypes",
|
|
40
41
|
"CustomStrings",
|
|
42
|
+
"DecompilationManager",
|
|
41
43
|
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# pylint:disable=import-outside-toplevel
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Any, TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from .plugin import KnowledgeBasePlugin
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from angr.analyses.decompiler.decompilation_cache import DecompilationCache
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DecompilationManager(KnowledgeBasePlugin):
|
|
13
|
+
"""A knowledge base plugin to store decompilation results."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, kb):
|
|
16
|
+
super().__init__(kb=kb)
|
|
17
|
+
self.cached: dict[Any, DecompilationCache] = {}
|
|
18
|
+
|
|
19
|
+
def _normalize_key(self, item: int | str):
|
|
20
|
+
if type(item) is str:
|
|
21
|
+
item = (self._kb.labels.lookup(item[0]), *item[1:])
|
|
22
|
+
return item
|
|
23
|
+
|
|
24
|
+
def __getitem__(self, item) -> DecompilationCache:
|
|
25
|
+
return self.cached[self._normalize_key(item)]
|
|
26
|
+
|
|
27
|
+
def __setitem__(self, key, value: DecompilationCache):
|
|
28
|
+
self.cached[self._normalize_key(key)] = value
|
|
29
|
+
|
|
30
|
+
def __contains__(self, key):
|
|
31
|
+
return self._normalize_key(key) in self.cached
|
|
32
|
+
|
|
33
|
+
def __delitem__(self, key):
|
|
34
|
+
del self.cached[self._normalize_key(key)]
|
|
35
|
+
|
|
36
|
+
def discard(self, key):
|
|
37
|
+
normalized_key = self._normalize_key(key)
|
|
38
|
+
if normalized_key in self.cached:
|
|
39
|
+
del self.cached[normalized_key]
|
|
40
|
+
|
|
41
|
+
def copy(self):
|
|
42
|
+
raise NotImplementedError
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
KnowledgeBasePlugin.register_default("decompilations", DecompilationManager)
|
|
@@ -277,6 +277,10 @@ class VirtualVariable(Atom):
|
|
|
277
277
|
def was_parameter(self) -> bool:
|
|
278
278
|
return self.category == ailment.Expr.VirtualVariableCategory.PARAMETER
|
|
279
279
|
|
|
280
|
+
@property
|
|
281
|
+
def was_tmp(self) -> bool:
|
|
282
|
+
return self.category == ailment.Expr.VirtualVariableCategory.TMP
|
|
283
|
+
|
|
280
284
|
@property
|
|
281
285
|
def reg_offset(self) -> int | None:
|
|
282
286
|
if self.was_reg:
|
|
@@ -289,6 +293,10 @@ class VirtualVariable(Atom):
|
|
|
289
293
|
return self.oident
|
|
290
294
|
return None
|
|
291
295
|
|
|
296
|
+
@property
|
|
297
|
+
def tmp_idx(self) -> int | None:
|
|
298
|
+
return self.oident if self.was_tmp else None
|
|
299
|
+
|
|
292
300
|
|
|
293
301
|
class MemoryLocation(Atom):
|
|
294
302
|
"""
|
|
@@ -162,7 +162,8 @@ def do_it(in_dir, out_file):
|
|
|
162
162
|
|
|
163
163
|
for file in files:
|
|
164
164
|
logging.info("Found file %s", file)
|
|
165
|
-
|
|
165
|
+
with codecs.open(file, "r", "utf-8-sig") as f:
|
|
166
|
+
api_namespaces[file.stem] = json.load(f)
|
|
166
167
|
|
|
167
168
|
logging.info("Making a bunch of types...")
|
|
168
169
|
missing_types_last_round = set()
|
|
@@ -7,7 +7,7 @@ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class ActionsMixinHigh(MemoryMixin):
|
|
10
|
-
def load(self, addr, size=None, condition=None, fallback=None, disable_actions=False, action=None, **kwargs):
|
|
10
|
+
def load(self, addr, size=None, *, condition=None, fallback=None, disable_actions=False, action=None, **kwargs):
|
|
11
11
|
if not disable_actions and o.AUTO_REFS in self.state.options and action is None:
|
|
12
12
|
action = self.__make_action("read", addr, size, None, condition, fallback)
|
|
13
13
|
|
|
@@ -28,7 +28,7 @@ class ActionsMixinHigh(MemoryMixin):
|
|
|
28
28
|
|
|
29
29
|
return r
|
|
30
30
|
|
|
31
|
-
def store(self, addr, data, size=None, disable_actions=False, action=None, condition=None, **kwargs):
|
|
31
|
+
def store(self, addr, data, size=None, *, disable_actions=False, action=None, condition=None, **kwargs):
|
|
32
32
|
if not disable_actions and o.AUTO_REFS in self.state.options and action is None:
|
|
33
33
|
action = self.__make_action("write", addr, size, data, condition, None)
|
|
34
34
|
|
|
@@ -49,24 +49,24 @@ class ActionsMixinHigh(MemoryMixin):
|
|
|
49
49
|
action.added_constraints = claripy.true()
|
|
50
50
|
return action
|
|
51
51
|
|
|
52
|
-
def _add_constraints(self, c, action=None, **kwargs):
|
|
52
|
+
def _add_constraints(self, c, *, action=None, **kwargs):
|
|
53
53
|
if action is not None:
|
|
54
54
|
action.added_constraints = claripy.And(action.added_constraints, c)
|
|
55
55
|
return super()._add_constraints(c, action=action, **kwargs)
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
class ActionsMixinLow(MemoryMixin):
|
|
59
|
-
def load(self, addr, action=None, **kwargs):
|
|
59
|
+
def load(self, addr, size=None, *, action=None, **kwargs):
|
|
60
60
|
if action is not None:
|
|
61
61
|
if action.actual_addrs is None:
|
|
62
62
|
action.actual_addrs = []
|
|
63
63
|
action.actual_addrs.append(addr)
|
|
64
|
-
return super().load(addr, action=action, **kwargs)
|
|
64
|
+
return super().load(addr, size, action=action, **kwargs)
|
|
65
65
|
|
|
66
|
-
def store(self, addr, data, action: SimActionData | None = None, **kwargs):
|
|
66
|
+
def store(self, addr, data, size=None, *, action: SimActionData | None = None, **kwargs):
|
|
67
67
|
if action is not None:
|
|
68
68
|
if action.actual_addrs is None:
|
|
69
69
|
action.actual_addrs = []
|
|
70
70
|
action.actual_addrs.append(addr)
|
|
71
71
|
action.actual_value = action._make_object(data)
|
|
72
|
-
return super().store(addr, data, action=action, **kwargs)
|
|
72
|
+
return super().store(addr, data, size, action=action, **kwargs)
|
|
@@ -230,7 +230,7 @@ class AddressConcretizationMixin(MemoryMixin):
|
|
|
230
230
|
"""
|
|
231
231
|
Take a list of integers and return a new list of integers where front and back integers interleave.
|
|
232
232
|
"""
|
|
233
|
-
lst = [
|
|
233
|
+
lst = [0xFACE] * len(addrs)
|
|
234
234
|
front, back = 0, len(addrs) - 1
|
|
235
235
|
i = 0
|
|
236
236
|
while front <= back:
|
|
@@ -257,7 +257,7 @@ class AddressConcretizationMixin(MemoryMixin):
|
|
|
257
257
|
return sub_value
|
|
258
258
|
return claripy.If(addr == concrete_addr, sub_value, read_value)
|
|
259
259
|
|
|
260
|
-
def load(self, addr, size=None, condition=None, **kwargs):
|
|
260
|
+
def load(self, addr, size=None, *, condition=None, **kwargs):
|
|
261
261
|
if type(size) is not int:
|
|
262
262
|
raise TypeError("Size must have been specified as an int before reaching address concretization")
|
|
263
263
|
|
|
@@ -309,7 +309,7 @@ class AddressConcretizationMixin(MemoryMixin):
|
|
|
309
309
|
sub_condition = condition & sub_condition
|
|
310
310
|
super().store(concrete_addr, data, size=size, condition=sub_condition, **kwargs)
|
|
311
311
|
|
|
312
|
-
def store(self, addr, data, size=None, condition=None, **kwargs):
|
|
312
|
+
def store(self, addr, data, size=None, *, condition=None, **kwargs):
|
|
313
313
|
# Fast path
|
|
314
314
|
if type(addr) is int:
|
|
315
315
|
self._store_one_addr(addr, data, True, addr, condition, size, **kwargs)
|
|
@@ -374,11 +374,11 @@ class AddressConcretizationMixin(MemoryMixin):
|
|
|
374
374
|
raise SimMemoryAddressError("Cannot unmap a region for a symbolic address")
|
|
375
375
|
return super().unmap_region(addr, length, **kwargs)
|
|
376
376
|
|
|
377
|
-
def concrete_load(self, addr, size,
|
|
377
|
+
def concrete_load(self, addr, size, writing=False, **kwargs):
|
|
378
378
|
if type(addr) is int:
|
|
379
379
|
pass
|
|
380
380
|
elif getattr(addr, "op", None) == "BVV":
|
|
381
381
|
addr = addr.args[0]
|
|
382
382
|
else:
|
|
383
383
|
raise SimMemoryAddressError("Cannot unmap a region for a symbolic address")
|
|
384
|
-
return super().concrete_load(addr, size,
|
|
384
|
+
return super().concrete_load(addr, size, writing=writing, **kwargs)
|
|
@@ -26,7 +26,7 @@ class DataNormalizationMixin(MemoryMixin):
|
|
|
26
26
|
|
|
27
27
|
super().store(addr, data_bv, size=size, **kwargs)
|
|
28
28
|
|
|
29
|
-
def load(self, addr, size=None, fallback=None, **kwargs):
|
|
29
|
+
def load(self, addr, size=None, *, fallback=None, **kwargs):
|
|
30
30
|
fallback_bv = self._convert_to_ast(fallback, size, self.state.arch.byte_width) if fallback is not None else None
|
|
31
31
|
return super().load(addr, size=size, fallback=fallback_bv, **kwargs)
|
|
32
32
|
|
|
@@ -4,7 +4,7 @@ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class InspectMixinHigh(MemoryMixin):
|
|
7
|
-
def store(self, addr, data, size=None, condition=None, endness=None, inspect=True, **kwargs):
|
|
7
|
+
def store(self, addr, data, size=None, *, condition=None, endness=None, inspect=True, **kwargs):
|
|
8
8
|
if not inspect or not self.state.supports_inspect:
|
|
9
9
|
super().store(addr, data, size=size, condition=condition, endness=endness, inspect=inspect, **kwargs)
|
|
10
10
|
return
|
|
@@ -63,7 +63,7 @@ class InspectMixinHigh(MemoryMixin):
|
|
|
63
63
|
mem_write_endness=endness,
|
|
64
64
|
)
|
|
65
65
|
|
|
66
|
-
def load(self, addr, size=None, condition=None, endness=None, inspect=True, **kwargs):
|
|
66
|
+
def load(self, addr, size=None, *, condition=None, endness=None, inspect=True, **kwargs):
|
|
67
67
|
if not inspect or not self.state.supports_inspect:
|
|
68
68
|
return super().load(addr, size=size, condition=condition, endness=endness, inspect=inspect, **kwargs)
|
|
69
69
|
|
|
@@ -122,7 +122,7 @@ class InspectMixinHigh(MemoryMixin):
|
|
|
122
122
|
|
|
123
123
|
return r
|
|
124
124
|
|
|
125
|
-
def _add_constraints(self, c, add_constraints=True, inspect=True, **kwargs):
|
|
125
|
+
def _add_constraints(self, c, *, add_constraints=True, inspect=True, **kwargs):
|
|
126
126
|
if inspect and self.state.supports_inspect:
|
|
127
127
|
# tracer uses address_concretization_add_constraints
|
|
128
128
|
add_constraints = self.state._inspect_getattr("address_concretization_add_constraints", add_constraints)
|
|
@@ -5,13 +5,13 @@ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class ConditionalMixin(MemoryMixin):
|
|
8
|
-
def load(self, addr, condition=None, fallback=None, **kwargs):
|
|
9
|
-
res = super().load(addr, condition=condition, **kwargs)
|
|
8
|
+
def load(self, addr, size=None, *, condition=None, fallback=None, **kwargs):
|
|
9
|
+
res = super().load(addr, size, condition=condition, **kwargs)
|
|
10
10
|
if condition is not None and fallback is not None:
|
|
11
11
|
res = claripy.If(condition, res, fallback)
|
|
12
12
|
return res
|
|
13
13
|
|
|
14
|
-
def store(self, addr, data, size=None, condition=None, **kwargs):
|
|
14
|
+
def store(self, addr, data, size=None, *, condition=None, **kwargs):
|
|
15
15
|
condition = self.state._adjust_condition(condition)
|
|
16
16
|
|
|
17
17
|
if condition is None or self.state.solver.is_true(condition):
|