angr 9.2.122__py3-none-win_amd64.whl → 9.2.124__py3-none-win_amd64.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.py +6 -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 +38 -342
- angr/analyses/decompiler/callsite_maker.py +8 -7
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +24 -2
- angr/analyses/decompiler/clinic.py +30 -3
- 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 +65 -2
- angr/analyses/decompiler/expression_narrower.py +206 -6
- 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 +34 -11
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +10 -1
- 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 +75 -42
- angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +8 -2
- angr/analyses/decompiler/region_identifier.py +36 -0
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +4 -0
- angr/analyses/decompiler/region_simplifiers/loop.py +2 -8
- angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +9 -3
- angr/analyses/decompiler/sequence_walker.py +20 -4
- 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 +26 -15
- 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/calling_conventions.py +2 -2
- angr/engines/light/engine.py +24 -2
- angr/engines/soot/expressions/instanceOf.py +4 -1
- angr/engines/successors.py +1 -1
- angr/engines/vex/heavy/concretizers.py +47 -47
- angr/engines/vex/heavy/dirty.py +4 -4
- angr/knowledge_plugins/__init__.py +2 -0
- angr/knowledge_plugins/decompilation.py +45 -0
- angr/knowledge_plugins/key_definitions/atoms.py +8 -0
- angr/lib/angr_native.dll +0 -0
- angr/procedures/definitions/parse_win32json.py +2 -1
- angr/procedures/java_lang/getsimplename.py +4 -1
- angr/procedures/linux_kernel/iovec.py +5 -2
- angr/sim_type.py +3 -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.122.dist-info → angr-9.2.124.dist-info}/METADATA +7 -6
- {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/RECORD +96 -95
- {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/WHEEL +1 -1
- {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/LICENSE +0 -0
- {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/entry_points.txt +0 -0
- {angr-9.2.122.dist-info → angr-9.2.124.dist-info}/top_level.txt +0 -0
|
@@ -9,7 +9,7 @@ import networkx
|
|
|
9
9
|
import ailment
|
|
10
10
|
from ailment import Block
|
|
11
11
|
from ailment.expression import Expression, Phi, VirtualVariable, VirtualVariableCategory
|
|
12
|
-
from ailment.statement import Assignment, Label
|
|
12
|
+
from ailment.statement import Statement, Assignment, Label
|
|
13
13
|
|
|
14
14
|
from angr.code_location import CodeLocation
|
|
15
15
|
from angr.analyses import ForwardAnalysis
|
|
@@ -38,6 +38,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
38
38
|
udef_to_phiid: dict[tuple, set[int]],
|
|
39
39
|
phiid_to_loc: dict[int, tuple[int, int | None]],
|
|
40
40
|
stackvar_locs: dict[int, int],
|
|
41
|
+
rewrite_tmps: bool,
|
|
41
42
|
ail_manager,
|
|
42
43
|
vvar_id_start: int = 0,
|
|
43
44
|
):
|
|
@@ -52,6 +53,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
52
53
|
self._udef_to_phiid = udef_to_phiid
|
|
53
54
|
self._phiid_to_loc = phiid_to_loc
|
|
54
55
|
self._stackvar_locs = stackvar_locs
|
|
56
|
+
self._rewrite_tmps = rewrite_tmps
|
|
55
57
|
self._ail_manager = ail_manager
|
|
56
58
|
self._engine_ail = SimEngineSSARewriting(
|
|
57
59
|
self.project.arch,
|
|
@@ -61,6 +63,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
61
63
|
udef_to_phiid=self._udef_to_phiid,
|
|
62
64
|
phiid_to_loc=self._phiid_to_loc,
|
|
63
65
|
stackvar_locs=self._stackvar_locs,
|
|
66
|
+
rewrite_tmps=self._rewrite_tmps,
|
|
64
67
|
ail_manager=ail_manager,
|
|
65
68
|
vvar_id_start=vvar_id_start,
|
|
66
69
|
)
|
|
@@ -71,7 +74,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
71
74
|
|
|
72
75
|
self._analyze()
|
|
73
76
|
|
|
74
|
-
self.def_to_vvid: dict[Expression, int] = self._engine_ail.def_to_vvid
|
|
77
|
+
self.def_to_vvid: dict[tuple[int, int | None, int, Expression | Statement], int] = self._engine_ail.def_to_vvid
|
|
75
78
|
self.out_graph = self._make_new_graph(ail_graph)
|
|
76
79
|
|
|
77
80
|
@property
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# pylint:disable=no-self-use,unused-argument
|
|
2
2
|
from __future__ import annotations
|
|
3
|
-
from typing import Any
|
|
4
3
|
import logging
|
|
5
4
|
|
|
6
|
-
from ailment.statement import Statement, Assignment, Store, Call, Return, ConditionalJump
|
|
5
|
+
from ailment.statement import Statement, Assignment, Store, Call, Return, ConditionalJump, DirtyStatement
|
|
7
6
|
from ailment.expression import (
|
|
8
7
|
Expression,
|
|
9
8
|
Register,
|
|
@@ -18,6 +17,8 @@ from ailment.expression import (
|
|
|
18
17
|
StackBaseOffset,
|
|
19
18
|
VEXCCallExpression,
|
|
20
19
|
ITE,
|
|
20
|
+
Tmp,
|
|
21
|
+
DirtyExpression,
|
|
21
22
|
)
|
|
22
23
|
|
|
23
24
|
from angr.utils.ssa import get_reg_offset_base_and_size
|
|
@@ -51,6 +52,7 @@ class SimEngineSSARewriting(
|
|
|
51
52
|
ail_manager=None,
|
|
52
53
|
vvar_id_start: int = 0,
|
|
53
54
|
bp_as_gpr: bool = False,
|
|
55
|
+
rewrite_tmps: bool = False,
|
|
54
56
|
):
|
|
55
57
|
super().__init__()
|
|
56
58
|
|
|
@@ -58,10 +60,11 @@ class SimEngineSSARewriting(
|
|
|
58
60
|
self.project = project
|
|
59
61
|
self.sp_tracker = sp_tracker
|
|
60
62
|
self.bp_as_gpr = bp_as_gpr
|
|
61
|
-
self.def_to_vvid: dict[
|
|
63
|
+
self.def_to_vvid: dict[tuple[int, int | None, int, Expression | Statement], int] = {}
|
|
62
64
|
self.stackvar_locs = stackvar_locs
|
|
63
65
|
self.udef_to_phiid = udef_to_phiid
|
|
64
66
|
self.phiid_to_loc = phiid_to_loc
|
|
67
|
+
self.rewrite_tmps = rewrite_tmps
|
|
65
68
|
self.ail_manager = ail_manager
|
|
66
69
|
|
|
67
70
|
self._current_vvar_id = vvar_id_start
|
|
@@ -97,9 +100,11 @@ class SimEngineSSARewriting(
|
|
|
97
100
|
self.state.registers[stmt.dst.reg_offset][stmt.dst.size] = stmt.dst
|
|
98
101
|
elif stmt.dst.category == VirtualVariableCategory.STACK:
|
|
99
102
|
self.state.stackvars[stmt.dst.stack_offset][stmt.dst.size] = stmt.dst
|
|
103
|
+
elif stmt.dst.category == VirtualVariableCategory.TMP:
|
|
104
|
+
self.state.tmps[stmt.dst.tmp_idx] = stmt.dst
|
|
100
105
|
new_dst = None
|
|
101
106
|
else:
|
|
102
|
-
new_dst = self._replace_def_expr(stmt.dst)
|
|
107
|
+
new_dst = self._replace_def_expr(self.block.addr, self.block.idx, self.stmt_idx, stmt.dst)
|
|
103
108
|
|
|
104
109
|
stmt_base_reg = None
|
|
105
110
|
if new_dst is not None:
|
|
@@ -124,7 +129,9 @@ class SimEngineSSARewriting(
|
|
|
124
129
|
**stmt.dst.tags,
|
|
125
130
|
)
|
|
126
131
|
existing_base_reg_vvar = self._replace_use_reg(base_reg_expr)
|
|
127
|
-
base_reg_vvar = self._replace_def_expr(
|
|
132
|
+
base_reg_vvar = self._replace_def_expr(
|
|
133
|
+
self.block.addr, self.block.idx, self.stmt_idx, base_reg_expr
|
|
134
|
+
)
|
|
128
135
|
stmt_base_reg = Assignment(
|
|
129
136
|
self.ail_manager.next_atom(),
|
|
130
137
|
base_reg_vvar,
|
|
@@ -134,6 +141,8 @@ class SimEngineSSARewriting(
|
|
|
134
141
|
**stmt.tags,
|
|
135
142
|
)
|
|
136
143
|
self.state.registers[base_offset][base_size] = base_reg_vvar
|
|
144
|
+
elif isinstance(stmt.dst, Tmp):
|
|
145
|
+
pass
|
|
137
146
|
else:
|
|
138
147
|
raise NotImplementedError
|
|
139
148
|
|
|
@@ -151,7 +160,7 @@ class SimEngineSSARewriting(
|
|
|
151
160
|
|
|
152
161
|
def _handle_Store(self, stmt: Store) -> Store | Assignment | None:
|
|
153
162
|
new_data = self._expr(stmt.data)
|
|
154
|
-
vvar = self._replace_def_store(stmt)
|
|
163
|
+
vvar = self._replace_def_store(self.block.addr, self.block.idx, self.stmt_idx, stmt)
|
|
155
164
|
if vvar is not None:
|
|
156
165
|
return Assignment(stmt.idx, vvar, stmt.data if new_data is None else new_data, **stmt.tags)
|
|
157
166
|
|
|
@@ -189,9 +198,19 @@ class SimEngineSSARewriting(
|
|
|
189
198
|
return None
|
|
190
199
|
|
|
191
200
|
def _handle_Call(self, stmt: Call) -> Call | None:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
201
|
+
changed = False
|
|
202
|
+
|
|
203
|
+
new_target = self._replace_use_expr(stmt.target)
|
|
204
|
+
new_ret_expr = (
|
|
205
|
+
self._replace_def_expr(self.block.addr, self.block.idx, self.stmt_idx, stmt.ret_expr)
|
|
206
|
+
if stmt.ret_expr is not None
|
|
207
|
+
else None
|
|
208
|
+
)
|
|
209
|
+
new_fp_ret_expr = (
|
|
210
|
+
self._replace_def_expr(self.block.addr, self.block.idx, self.stmt_idx, stmt.fp_ret_expr)
|
|
211
|
+
if stmt.fp_ret_expr is not None
|
|
212
|
+
else None
|
|
213
|
+
)
|
|
195
214
|
|
|
196
215
|
cc = stmt.calling_convention if stmt.calling_convention is not None else self.project.factory.cc()
|
|
197
216
|
if cc is not None:
|
|
@@ -211,22 +230,50 @@ class SimEngineSSARewriting(
|
|
|
211
230
|
self._clear_aliasing_regs(stmt.fp_ret_expr.reg_offset, stmt.fp_ret_expr.size)
|
|
212
231
|
self.state.registers[stmt.fp_ret_expr.reg_offset][stmt.fp_ret_expr.size] = new_fp_ret_expr
|
|
213
232
|
|
|
233
|
+
new_args = None
|
|
234
|
+
if stmt.args is not None:
|
|
235
|
+
new_args = []
|
|
236
|
+
for arg in stmt.args:
|
|
237
|
+
new_arg = self._expr(arg)
|
|
238
|
+
if new_arg is not None:
|
|
239
|
+
changed = True
|
|
240
|
+
new_args.append(new_arg)
|
|
241
|
+
else:
|
|
242
|
+
new_args.append(arg)
|
|
243
|
+
|
|
214
244
|
if new_target is not None or new_ret_expr is not None or new_fp_ret_expr is not None:
|
|
245
|
+
changed = True
|
|
246
|
+
|
|
247
|
+
if changed:
|
|
215
248
|
return Call(
|
|
216
249
|
stmt.idx,
|
|
217
250
|
stmt.target if new_target is None else new_target,
|
|
218
251
|
calling_convention=stmt.calling_convention,
|
|
219
252
|
prototype=stmt.prototype,
|
|
220
|
-
args=
|
|
253
|
+
args=new_args,
|
|
221
254
|
ret_expr=stmt.ret_expr if new_ret_expr is None else new_ret_expr,
|
|
222
255
|
fp_ret_expr=stmt.fp_ret_expr if new_fp_ret_expr is None else new_fp_ret_expr,
|
|
256
|
+
bits=stmt.bits,
|
|
223
257
|
**stmt.tags,
|
|
224
258
|
)
|
|
225
259
|
return None
|
|
226
260
|
|
|
261
|
+
_handle_CallExpr = _handle_Call
|
|
262
|
+
|
|
263
|
+
def _handle_DirtyStatement(self, stmt: DirtyStatement) -> DirtyStatement | None:
|
|
264
|
+
dirty = self._expr(stmt.dirty)
|
|
265
|
+
if dirty is None or dirty is stmt.dirty:
|
|
266
|
+
return None
|
|
267
|
+
return DirtyStatement(stmt.idx, dirty, **stmt.tags)
|
|
268
|
+
|
|
227
269
|
def _handle_Register(self, expr: Register) -> VirtualVariable | None:
|
|
228
270
|
return self._replace_use_reg(expr)
|
|
229
271
|
|
|
272
|
+
def _handle_Tmp(self, expr: Tmp) -> VirtualVariable | None:
|
|
273
|
+
return (
|
|
274
|
+
self._replace_use_tmp(self.block.addr, self.block.idx, self.stmt_idx, expr) if self.rewrite_tmps else None
|
|
275
|
+
)
|
|
276
|
+
|
|
230
277
|
def _handle_Load(self, expr: Load) -> Load | VirtualVariable | None:
|
|
231
278
|
if isinstance(expr.addr, StackBaseOffset) and isinstance(expr.addr.offset, int):
|
|
232
279
|
new_expr = self._replace_use_load(expr)
|
|
@@ -341,13 +388,42 @@ class SimEngineSSARewriting(
|
|
|
341
388
|
new_operands.append(operand)
|
|
342
389
|
|
|
343
390
|
if updated:
|
|
344
|
-
return VEXCCallExpression(expr.idx, expr.
|
|
391
|
+
return VEXCCallExpression(expr.idx, expr.callee, new_operands, bits=expr.bits, **expr.tags)
|
|
345
392
|
return None
|
|
346
393
|
|
|
347
|
-
def
|
|
394
|
+
def _handle_DirtyExpression(self, expr: DirtyExpression) -> DirtyExpression | None:
|
|
395
|
+
updated = False
|
|
396
|
+
new_operands = []
|
|
397
|
+
for operand in expr.operands:
|
|
398
|
+
new_operand = self._expr(operand)
|
|
399
|
+
if new_operand is not None:
|
|
400
|
+
updated = True
|
|
401
|
+
new_operands.append(new_operand)
|
|
402
|
+
else:
|
|
403
|
+
new_operands.append(operand)
|
|
404
|
+
|
|
405
|
+
new_guard = None
|
|
406
|
+
if expr.guard is not None:
|
|
407
|
+
new_guard = self._expr(expr.guard)
|
|
408
|
+
if new_guard is not None:
|
|
409
|
+
updated = True
|
|
410
|
+
|
|
411
|
+
if updated:
|
|
412
|
+
return DirtyExpression(
|
|
413
|
+
expr.idx,
|
|
414
|
+
expr.callee,
|
|
415
|
+
new_operands,
|
|
416
|
+
guard=new_guard,
|
|
417
|
+
mfx=expr.mfx,
|
|
418
|
+
maddr=expr.maddr,
|
|
419
|
+
msize=expr.msize,
|
|
420
|
+
bits=expr.bits,
|
|
421
|
+
**expr.tags,
|
|
422
|
+
)
|
|
348
423
|
return None
|
|
349
424
|
|
|
350
|
-
|
|
425
|
+
def _handle_Dummy(self, expr) -> None:
|
|
426
|
+
return None
|
|
351
427
|
|
|
352
428
|
#
|
|
353
429
|
# Expression replacement
|
|
@@ -417,23 +493,29 @@ class SimEngineSSARewriting(
|
|
|
417
493
|
**new_base_expr.tags,
|
|
418
494
|
)
|
|
419
495
|
|
|
420
|
-
def _replace_def_expr(
|
|
496
|
+
def _replace_def_expr(
|
|
497
|
+
self, block_addr: int, block_idx: int | None, stmt_idx: int, thing: Expression | Statement
|
|
498
|
+
) -> VirtualVariable | None:
|
|
421
499
|
"""
|
|
422
500
|
Return a new virtual variable for the given defined expression.
|
|
423
501
|
"""
|
|
424
502
|
if isinstance(thing, Register):
|
|
425
|
-
return self._replace_def_reg(thing)
|
|
503
|
+
return self._replace_def_reg(block_addr, block_idx, stmt_idx, thing)
|
|
426
504
|
if isinstance(thing, Store):
|
|
427
|
-
return self._replace_def_store(thing)
|
|
505
|
+
return self._replace_def_store(block_addr, block_idx, stmt_idx, thing)
|
|
506
|
+
if isinstance(thing, Tmp) and self.rewrite_tmps:
|
|
507
|
+
return self._replace_def_tmp(block_addr, block_idx, stmt_idx, thing)
|
|
428
508
|
return None
|
|
429
509
|
|
|
430
|
-
def _replace_def_reg(
|
|
510
|
+
def _replace_def_reg(
|
|
511
|
+
self, block_addr: int, block_idx: int | None, stmt_idx: int, expr: Register
|
|
512
|
+
) -> VirtualVariable:
|
|
431
513
|
"""
|
|
432
514
|
Return a new virtual variable for the given defined register.
|
|
433
515
|
"""
|
|
434
516
|
|
|
435
517
|
# get the virtual variable ID
|
|
436
|
-
vvid = self.get_vvid_by_def(expr)
|
|
518
|
+
vvid = self.get_vvid_by_def(block_addr, block_idx, stmt_idx, expr)
|
|
437
519
|
return VirtualVariable(
|
|
438
520
|
expr.idx,
|
|
439
521
|
vvid,
|
|
@@ -464,14 +546,16 @@ class SimEngineSSARewriting(
|
|
|
464
546
|
return vvar
|
|
465
547
|
return self.state.registers[base_off][base_size]
|
|
466
548
|
|
|
467
|
-
def _replace_def_store(
|
|
549
|
+
def _replace_def_store(
|
|
550
|
+
self, block_addr: int, block_idx: int | None, stmt_idx: int, stmt: Store
|
|
551
|
+
) -> VirtualVariable | None:
|
|
468
552
|
if (
|
|
469
553
|
isinstance(stmt.addr, StackBaseOffset)
|
|
470
554
|
and isinstance(stmt.addr.offset, int)
|
|
471
555
|
and stmt.addr.offset in self.stackvar_locs
|
|
472
556
|
and stmt.size == self.stackvar_locs[stmt.addr.offset]
|
|
473
557
|
):
|
|
474
|
-
vvar_id = self.get_vvid_by_def(stmt)
|
|
558
|
+
vvar_id = self.get_vvid_by_def(block_addr, block_idx, stmt_idx, stmt)
|
|
475
559
|
vvar = VirtualVariable(
|
|
476
560
|
self.ail_manager.next_atom(),
|
|
477
561
|
vvar_id,
|
|
@@ -484,6 +568,31 @@ class SimEngineSSARewriting(
|
|
|
484
568
|
return vvar
|
|
485
569
|
return None
|
|
486
570
|
|
|
571
|
+
def _replace_def_tmp(self, block_addr: int, block_idx: int | None, stmt_idx: int, expr: Tmp) -> VirtualVariable:
|
|
572
|
+
vvid = self.get_vvid_by_def(block_addr, block_idx, stmt_idx, expr)
|
|
573
|
+
vvar = VirtualVariable(
|
|
574
|
+
expr.idx,
|
|
575
|
+
vvid,
|
|
576
|
+
expr.bits,
|
|
577
|
+
VirtualVariableCategory.TMP,
|
|
578
|
+
oident=expr.tmp_idx,
|
|
579
|
+
**expr.tags,
|
|
580
|
+
)
|
|
581
|
+
self.state.tmps[expr.tmp_idx] = vvar
|
|
582
|
+
return vvar
|
|
583
|
+
|
|
584
|
+
def _replace_use_expr(self, thing: Expression | Statement) -> VirtualVariable | None:
|
|
585
|
+
"""
|
|
586
|
+
Return a new virtual variable for the given defined expression.
|
|
587
|
+
"""
|
|
588
|
+
if isinstance(thing, Register):
|
|
589
|
+
return self._replace_use_reg(thing)
|
|
590
|
+
if isinstance(thing, Store):
|
|
591
|
+
raise NotImplementedError("Store expressions are not supported in _replace_use_expr.")
|
|
592
|
+
if isinstance(thing, Tmp) and self.rewrite_tmps:
|
|
593
|
+
return self._replace_use_tmp(self.block.addr, self.block.idx, self.stmt_idx, thing)
|
|
594
|
+
return None
|
|
595
|
+
|
|
487
596
|
def _replace_use_reg(self, reg_expr: Register) -> VirtualVariable | Expression:
|
|
488
597
|
|
|
489
598
|
if reg_expr.reg_offset in self.state.registers:
|
|
@@ -556,7 +665,8 @@ class SimEngineSSARewriting(
|
|
|
556
665
|
and expr.size == self.stackvar_locs[expr.addr.offset]
|
|
557
666
|
):
|
|
558
667
|
if expr.size not in self.state.stackvars[expr.addr.offset]:
|
|
559
|
-
|
|
668
|
+
# create it on the fly
|
|
669
|
+
vvar_id = self.get_vvid_by_def(self.block.addr, self.block.idx, self.stmt_idx, expr)
|
|
560
670
|
return VirtualVariable(
|
|
561
671
|
self.ail_manager.next_atom(),
|
|
562
672
|
vvar_id,
|
|
@@ -579,15 +689,31 @@ class SimEngineSSARewriting(
|
|
|
579
689
|
)
|
|
580
690
|
return None
|
|
581
691
|
|
|
692
|
+
def _replace_use_tmp(self, block_addr: int, block_idx: int | None, stmt_idx: int, expr: Tmp) -> VirtualVariable:
|
|
693
|
+
vvar = self.state.tmps.get(expr.tmp_idx)
|
|
694
|
+
if vvar is None:
|
|
695
|
+
return self._replace_def_tmp(block_addr, block_idx, stmt_idx, expr)
|
|
696
|
+
return VirtualVariable(
|
|
697
|
+
expr.idx,
|
|
698
|
+
vvar.varid,
|
|
699
|
+
vvar.bits,
|
|
700
|
+
VirtualVariableCategory.TMP,
|
|
701
|
+
oident=expr.tmp_idx,
|
|
702
|
+
**expr.tags,
|
|
703
|
+
)
|
|
704
|
+
|
|
582
705
|
#
|
|
583
706
|
# Utils
|
|
584
707
|
#
|
|
585
708
|
|
|
586
|
-
def get_vvid_by_def(
|
|
587
|
-
|
|
588
|
-
|
|
709
|
+
def get_vvid_by_def(
|
|
710
|
+
self, block_addr: int, block_idx: int | None, stmt_idx: int, thing: Expression | Statement
|
|
711
|
+
) -> int:
|
|
712
|
+
key = block_addr, block_idx, stmt_idx, thing
|
|
713
|
+
if key in self.def_to_vvid:
|
|
714
|
+
return self.def_to_vvid[key]
|
|
589
715
|
vvid = self.next_vvar_id()
|
|
590
|
-
self.def_to_vvid[
|
|
716
|
+
self.def_to_vvid[key] = vvid
|
|
591
717
|
return vvid
|
|
592
718
|
|
|
593
719
|
def _clear_aliasing_regs(self, reg_offset: int, size: int, remove_base_reg: bool = True) -> None:
|
|
@@ -32,6 +32,7 @@ class RewritingState:
|
|
|
32
32
|
self.stackvars: defaultdict[int, dict[int, VirtualVariable]] = (
|
|
33
33
|
stackvars if stackvars is not None else defaultdict(dict)
|
|
34
34
|
)
|
|
35
|
+
self.tmps: dict[int, VirtualVariable] = {}
|
|
35
36
|
self.original_block = original_block
|
|
36
37
|
self.out_block = None
|
|
37
38
|
|
|
@@ -5,8 +5,8 @@ from collections import defaultdict
|
|
|
5
5
|
from itertools import count
|
|
6
6
|
from bisect import bisect_left
|
|
7
7
|
|
|
8
|
-
from ailment.expression import Register, StackBaseOffset
|
|
9
|
-
from ailment.statement import Store
|
|
8
|
+
from ailment.expression import Expression, Register, StackBaseOffset, Tmp
|
|
9
|
+
from ailment.statement import Statement, Store
|
|
10
10
|
|
|
11
11
|
from angr.knowledge_plugins.functions import Function
|
|
12
12
|
from angr.code_location import CodeLocation
|
|
@@ -33,6 +33,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
33
33
|
func_addr: int | None = None,
|
|
34
34
|
ail_manager=None,
|
|
35
35
|
ssa_stackvars: bool = False,
|
|
36
|
+
ssa_tmps: bool = False,
|
|
36
37
|
vvar_id_start: int = 0,
|
|
37
38
|
):
|
|
38
39
|
"""
|
|
@@ -51,6 +52,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
51
52
|
self._func_addr = func_addr
|
|
52
53
|
self._ail_manager = ail_manager
|
|
53
54
|
self._ssa_stackvars = ssa_stackvars
|
|
55
|
+
self._ssa_tmps = ssa_tmps
|
|
54
56
|
self._entry = (
|
|
55
57
|
entry
|
|
56
58
|
if entry is not None
|
|
@@ -68,6 +70,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
68
70
|
stack_pointer_tracker,
|
|
69
71
|
bp_as_gpr,
|
|
70
72
|
ssa_stackvars,
|
|
73
|
+
ssa_tmps,
|
|
71
74
|
)
|
|
72
75
|
|
|
73
76
|
# calculate virtual variables and phi nodes
|
|
@@ -86,13 +89,19 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
86
89
|
self._udef_to_phiid,
|
|
87
90
|
self._phiid_to_loc,
|
|
88
91
|
self._stackvar_locs,
|
|
92
|
+
self._ssa_tmps,
|
|
89
93
|
self._ail_manager,
|
|
90
94
|
vvar_id_start=vvar_id_start,
|
|
91
95
|
)
|
|
92
96
|
self.out_graph = rewriter.out_graph
|
|
93
97
|
self.max_vvar_id = rewriter.max_vvar_id
|
|
94
98
|
|
|
95
|
-
def _calculate_virtual_variables(
|
|
99
|
+
def _calculate_virtual_variables(
|
|
100
|
+
self,
|
|
101
|
+
ail_graph,
|
|
102
|
+
def_to_loc: list[tuple[Expression | Statement, CodeLocation]],
|
|
103
|
+
loc_to_defs: dict[CodeLocation, Any],
|
|
104
|
+
):
|
|
96
105
|
"""
|
|
97
106
|
Calculate the mapping from defs to virtual variables as well as where to insert phi nodes.
|
|
98
107
|
"""
|
|
@@ -112,7 +121,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
112
121
|
if self._ssa_stackvars:
|
|
113
122
|
# for stack variables, we collect all definitions and identify stack variable locations using heuristics
|
|
114
123
|
|
|
115
|
-
stackvar_locs = self._synthesize_stackvar_locs([def_ for def_ in def_to_loc if isinstance(def_, Store)])
|
|
124
|
+
stackvar_locs = self._synthesize_stackvar_locs([def_ for def_, _ in def_to_loc if isinstance(def_, Store)])
|
|
116
125
|
sorted_stackvar_offs = sorted(stackvar_locs)
|
|
117
126
|
else:
|
|
118
127
|
stackvar_locs = {}
|
|
@@ -121,10 +130,8 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
121
130
|
# computer phi node locations for each unified definition
|
|
122
131
|
udef_to_defs = defaultdict(set)
|
|
123
132
|
udef_to_blockkeys = defaultdict(set)
|
|
124
|
-
for def_ in def_to_loc:
|
|
133
|
+
for def_, loc in def_to_loc:
|
|
125
134
|
if isinstance(def_, Register):
|
|
126
|
-
loc = def_to_loc[def_]
|
|
127
|
-
|
|
128
135
|
base_off, base_size = get_reg_offset_base_and_size(def_.reg_offset, self.project.arch, size=def_.size)
|
|
129
136
|
base_reg_bits = base_size * self.project.arch.byte_width
|
|
130
137
|
udef_to_defs[("reg", base_off, base_reg_bits)].add(def_)
|
|
@@ -135,8 +142,6 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
135
142
|
udef_to_defs[("reg", def_.reg_offset, reg_bits)].add((loc.block_addr, loc.block_idx))
|
|
136
143
|
elif isinstance(def_, Store):
|
|
137
144
|
if isinstance(def_.addr, StackBaseOffset) and isinstance(def_.addr.offset, int):
|
|
138
|
-
loc = def_to_loc[def_]
|
|
139
|
-
|
|
140
145
|
idx_begin = bisect_left(sorted_stackvar_offs, def_.addr.offset)
|
|
141
146
|
for i in range(idx_begin, len(sorted_stackvar_offs)):
|
|
142
147
|
off = sorted_stackvar_offs[i]
|
|
@@ -144,6 +149,9 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
144
149
|
break
|
|
145
150
|
udef_to_defs[("stack", off, stackvar_locs[off])].add(def_)
|
|
146
151
|
udef_to_blockkeys[("stack", off, stackvar_locs[off])].add((loc.block_addr, loc.block_idx))
|
|
152
|
+
elif isinstance(def_, Tmp):
|
|
153
|
+
# Tmps are local to each block and do not need phi nodes
|
|
154
|
+
pass
|
|
147
155
|
else:
|
|
148
156
|
raise NotImplementedError
|
|
149
157
|
# other types are not supported yet
|
|
@@ -19,10 +19,11 @@ class TraversalAnalysis(ForwardAnalysis[None, NodeType, object, object]):
|
|
|
19
19
|
TraversalAnalysis traverses the AIL graph and collects definitions.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
def __init__(self, project, func, ail_graph, sp_tracker, bp_as_gpr: bool, stackvars: bool):
|
|
22
|
+
def __init__(self, project, func, ail_graph, sp_tracker, bp_as_gpr: bool, stackvars: bool, tmps: bool):
|
|
23
23
|
|
|
24
24
|
self.project = project
|
|
25
25
|
self._stackvars = stackvars
|
|
26
|
+
self._tmps = tmps
|
|
26
27
|
self._function = func
|
|
27
28
|
self._graph_visitor = FunctionGraphVisitor(self._function, ail_graph)
|
|
28
29
|
|
|
@@ -34,6 +35,7 @@ class TraversalAnalysis(ForwardAnalysis[None, NodeType, object, object]):
|
|
|
34
35
|
sp_tracker=sp_tracker,
|
|
35
36
|
bp_as_gpr=bp_as_gpr,
|
|
36
37
|
stackvars=self._stackvars,
|
|
38
|
+
tmps=self._tmps,
|
|
37
39
|
)
|
|
38
40
|
|
|
39
41
|
self._visited_blocks: set[Any] = set()
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
from collections import OrderedDict
|
|
3
3
|
|
|
4
4
|
from ailment.statement import Assignment, Call, Store, ConditionalJump
|
|
5
|
-
from ailment.expression import Register, BinaryOp, StackBaseOffset, ITE, VEXCCallExpression
|
|
5
|
+
from ailment.expression import Register, BinaryOp, StackBaseOffset, ITE, VEXCCallExpression, Tmp, DirtyExpression
|
|
6
6
|
|
|
7
7
|
from angr.engines.light import SimEngineLight, SimEngineLightAILMixin
|
|
8
8
|
from angr.utils.ssa import get_reg_offset_base
|
|
@@ -21,7 +21,14 @@ class SimEngineSSATraversal(
|
|
|
21
21
|
state: TraversalState
|
|
22
22
|
|
|
23
23
|
def __init__(
|
|
24
|
-
self,
|
|
24
|
+
self,
|
|
25
|
+
arch,
|
|
26
|
+
sp_tracker=None,
|
|
27
|
+
bp_as_gpr: bool = False,
|
|
28
|
+
def_to_loc=None,
|
|
29
|
+
loc_to_defs=None,
|
|
30
|
+
stackvars: bool = False,
|
|
31
|
+
tmps: bool = False,
|
|
25
32
|
):
|
|
26
33
|
super().__init__()
|
|
27
34
|
|
|
@@ -29,14 +36,15 @@ class SimEngineSSATraversal(
|
|
|
29
36
|
self.sp_tracker = sp_tracker
|
|
30
37
|
self.bp_as_gpr = bp_as_gpr
|
|
31
38
|
self.stackvars = stackvars
|
|
39
|
+
self.tmps = tmps
|
|
32
40
|
|
|
33
|
-
self.def_to_loc = def_to_loc if def_to_loc is not None else
|
|
41
|
+
self.def_to_loc = def_to_loc if def_to_loc is not None else []
|
|
34
42
|
self.loc_to_defs = loc_to_defs if loc_to_defs is not None else OrderedDict()
|
|
35
43
|
|
|
36
44
|
def _handle_Assignment(self, stmt: Assignment):
|
|
37
45
|
if isinstance(stmt.dst, Register):
|
|
38
46
|
codeloc = self._codeloc()
|
|
39
|
-
self.def_to_loc
|
|
47
|
+
self.def_to_loc.append((stmt.dst, codeloc))
|
|
40
48
|
if codeloc not in self.loc_to_defs:
|
|
41
49
|
self.loc_to_defs[codeloc] = OrderedSet()
|
|
42
50
|
self.loc_to_defs[codeloc].add(stmt.dst)
|
|
@@ -52,7 +60,7 @@ class SimEngineSSATraversal(
|
|
|
52
60
|
|
|
53
61
|
if self.stackvars and isinstance(stmt.addr, StackBaseOffset) and isinstance(stmt.addr.offset, int):
|
|
54
62
|
codeloc = self._codeloc()
|
|
55
|
-
self.def_to_loc
|
|
63
|
+
self.def_to_loc.append((stmt, codeloc))
|
|
56
64
|
if codeloc not in self.loc_to_defs:
|
|
57
65
|
self.loc_to_defs[codeloc] = OrderedSet()
|
|
58
66
|
self.loc_to_defs[codeloc].add(stmt)
|
|
@@ -69,7 +77,7 @@ class SimEngineSSATraversal(
|
|
|
69
77
|
def _handle_Call(self, stmt: Call):
|
|
70
78
|
if stmt.ret_expr is not None and isinstance(stmt.ret_expr, Register):
|
|
71
79
|
codeloc = self._codeloc()
|
|
72
|
-
self.def_to_loc
|
|
80
|
+
self.def_to_loc.append((stmt.ret_expr, codeloc))
|
|
73
81
|
if codeloc not in self.loc_to_defs:
|
|
74
82
|
self.loc_to_defs[codeloc] = OrderedSet()
|
|
75
83
|
self.loc_to_defs[codeloc].add(stmt.ret_expr)
|
|
@@ -79,18 +87,30 @@ class SimEngineSSATraversal(
|
|
|
79
87
|
|
|
80
88
|
super()._ail_handle_Call(stmt)
|
|
81
89
|
|
|
90
|
+
_handle_CallExpr = _handle_Call
|
|
91
|
+
|
|
82
92
|
def _handle_Register(self, expr: Register):
|
|
83
93
|
base_offset = get_reg_offset_base(expr.reg_offset, self.arch)
|
|
84
94
|
|
|
85
95
|
if base_offset not in self.state.live_registers:
|
|
86
96
|
codeloc = self._codeloc()
|
|
87
|
-
self.def_to_loc
|
|
97
|
+
self.def_to_loc.append((expr, codeloc))
|
|
88
98
|
if codeloc not in self.loc_to_defs:
|
|
89
99
|
self.loc_to_defs[codeloc] = OrderedSet()
|
|
90
100
|
self.loc_to_defs[codeloc].add(expr)
|
|
91
101
|
|
|
92
102
|
self.state.live_registers.add(base_offset)
|
|
93
103
|
|
|
104
|
+
def _handle_Tmp(self, expr: Tmp):
|
|
105
|
+
if self.tmps:
|
|
106
|
+
codeloc = self._codeloc()
|
|
107
|
+
self.def_to_loc.append((expr, codeloc))
|
|
108
|
+
if codeloc not in self.loc_to_defs:
|
|
109
|
+
self.loc_to_defs[codeloc] = OrderedSet()
|
|
110
|
+
self.loc_to_defs[codeloc].add(expr)
|
|
111
|
+
|
|
112
|
+
self.state.live_tmps.add(expr.tmp_idx)
|
|
113
|
+
|
|
94
114
|
def _handle_Cmp(self, expr: BinaryOp):
|
|
95
115
|
self._expr(expr.operands[0])
|
|
96
116
|
self._expr(expr.operands[1])
|
|
@@ -123,9 +143,16 @@ class SimEngineSSATraversal(
|
|
|
123
143
|
for operand in expr.operands:
|
|
124
144
|
self._expr(operand)
|
|
125
145
|
|
|
146
|
+
def _handle_DirtyExpression(self, expr: DirtyExpression):
|
|
147
|
+
for operand in expr.operands:
|
|
148
|
+
self._expr(operand)
|
|
149
|
+
if expr.guard is not None:
|
|
150
|
+
self._expr(expr.guard)
|
|
151
|
+
if expr.maddr is not None:
|
|
152
|
+
self._expr(expr.maddr)
|
|
153
|
+
|
|
126
154
|
def _handle_Dummy(self, expr):
|
|
127
155
|
pass
|
|
128
156
|
|
|
129
157
|
_handle_VirtualVariable = _handle_Dummy
|
|
130
158
|
_handle_Phi = _handle_Dummy
|
|
131
|
-
_handle_DirtyExpression = _handle_Dummy
|
|
@@ -18,6 +18,7 @@ class TraversalState:
|
|
|
18
18
|
|
|
19
19
|
self.live_registers: set[int] = set() if live_registers is None else live_registers
|
|
20
20
|
self.live_stackvars: set[tuple[int, int]] = set() if live_stackvars is None else live_stackvars
|
|
21
|
+
self.live_tmps: set[int] = set() # tmps are internal to a block only and never propagated from another state
|
|
21
22
|
|
|
22
23
|
def copy(self) -> TraversalState:
|
|
23
24
|
return TraversalState(
|