angr 9.2.122__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/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/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 +95 -94
- {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
|
@@ -1408,7 +1408,7 @@ class CUnsupportedStatement(CStatement):
|
|
|
1408
1408
|
class CDirtyStatement(CExpression):
|
|
1409
1409
|
__slots__ = ("dirty",)
|
|
1410
1410
|
|
|
1411
|
-
def __init__(self, dirty, **kwargs):
|
|
1411
|
+
def __init__(self, dirty: CDirtyExpression, **kwargs):
|
|
1412
1412
|
super().__init__(**kwargs)
|
|
1413
1413
|
self.dirty = dirty
|
|
1414
1414
|
|
|
@@ -1420,7 +1420,7 @@ class CDirtyStatement(CExpression):
|
|
|
1420
1420
|
indent_str = self.indent_str(indent=indent)
|
|
1421
1421
|
|
|
1422
1422
|
yield indent_str, None
|
|
1423
|
-
yield
|
|
1423
|
+
yield from self.dirty.c_repr_chunks()
|
|
1424
1424
|
yield "\n", None
|
|
1425
1425
|
|
|
1426
1426
|
|
|
@@ -2303,6 +2303,38 @@ class CMultiStatementExpression(CExpression):
|
|
|
2303
2303
|
yield ")", paren
|
|
2304
2304
|
|
|
2305
2305
|
|
|
2306
|
+
class CVEXCCallExpression(CExpression):
|
|
2307
|
+
"""
|
|
2308
|
+
ccall_name(arg0, arg1, ...)
|
|
2309
|
+
"""
|
|
2310
|
+
|
|
2311
|
+
__slots__ = (
|
|
2312
|
+
"callee",
|
|
2313
|
+
"operands",
|
|
2314
|
+
"tags",
|
|
2315
|
+
)
|
|
2316
|
+
|
|
2317
|
+
def __init__(self, callee: str, operands: list[CExpression], tags=None, **kwargs):
|
|
2318
|
+
super().__init__(**kwargs)
|
|
2319
|
+
self.callee = callee
|
|
2320
|
+
self.operands = operands
|
|
2321
|
+
self.tags = tags
|
|
2322
|
+
|
|
2323
|
+
@property
|
|
2324
|
+
def type(self):
|
|
2325
|
+
return SimTypeInt().with_arch(self.codegen.project.arch)
|
|
2326
|
+
|
|
2327
|
+
def c_repr_chunks(self, indent=0, asexpr=False):
|
|
2328
|
+
paren = CClosingObject("(")
|
|
2329
|
+
yield f"{self.callee}", self
|
|
2330
|
+
yield "(", paren
|
|
2331
|
+
for idx, operand in enumerate(self.operands):
|
|
2332
|
+
if idx != 0:
|
|
2333
|
+
yield ", ", None
|
|
2334
|
+
yield from operand.c_repr_chunks()
|
|
2335
|
+
yield ")", paren
|
|
2336
|
+
|
|
2337
|
+
|
|
2306
2338
|
class CDirtyExpression(CExpression):
|
|
2307
2339
|
"""
|
|
2308
2340
|
Ideally all dirty expressions should be handled and converted to proper conversions during conversion from VEX to
|
|
@@ -2424,6 +2456,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
2424
2456
|
Expr.BinaryOp: self._handle_Expr_BinaryOp,
|
|
2425
2457
|
Expr.Convert: self._handle_Expr_Convert,
|
|
2426
2458
|
Expr.StackBaseOffset: self._handle_Expr_StackBaseOffset,
|
|
2459
|
+
Expr.VEXCCallExpression: self._handle_Expr_VEXCCallExpression,
|
|
2427
2460
|
Expr.DirtyExpression: self._handle_Expr_Dirty,
|
|
2428
2461
|
Expr.ITE: self._handle_Expr_ITE,
|
|
2429
2462
|
Expr.Reinterpret: self._handle_Reinterpret,
|
|
@@ -3318,7 +3351,8 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3318
3351
|
return clabel
|
|
3319
3352
|
|
|
3320
3353
|
def _handle_Stmt_Dirty(self, stmt: Stmt.DirtyStatement, **kwargs):
|
|
3321
|
-
|
|
3354
|
+
dirty = self._handle(stmt.dirty)
|
|
3355
|
+
return CDirtyStatement(dirty, codegen=self)
|
|
3322
3356
|
|
|
3323
3357
|
#
|
|
3324
3358
|
# AIL expression handlers
|
|
@@ -3519,7 +3553,11 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3519
3553
|
|
|
3520
3554
|
return CTypeCast(None, dst_type.with_arch(self.project.arch), child, tags=expr.tags, codegen=self)
|
|
3521
3555
|
|
|
3522
|
-
def
|
|
3556
|
+
def _handle_Expr_VEXCCallExpression(self, expr: Expr.VEXCCallExpression, **kwargs):
|
|
3557
|
+
operands = [self._handle(arg) for arg in expr.operands]
|
|
3558
|
+
return CVEXCCallExpression(expr.callee, operands, tags=expr.tags, codegen=self)
|
|
3559
|
+
|
|
3560
|
+
def _handle_Expr_Dirty(self, expr: Expr.DirtyExpression, **kwargs):
|
|
3523
3561
|
return CDirtyExpression(expr, codegen=self)
|
|
3524
3562
|
|
|
3525
3563
|
def _handle_Expr_ITE(self, expr: Expr.ITE, **kwargs):
|
|
@@ -566,6 +566,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
566
566
|
|
|
567
567
|
if next_node is node:
|
|
568
568
|
break
|
|
569
|
+
if next_node is head:
|
|
570
|
+
# we don't want a loop with region head not as the first node of the body!
|
|
571
|
+
return False, None
|
|
569
572
|
if next_node is not node and next_node in seen_nodes:
|
|
570
573
|
return False, None
|
|
571
574
|
|
|
@@ -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
|
@@ -5,7 +5,7 @@ from collections import defaultdict
|
|
|
5
5
|
|
|
6
6
|
from ailment.block import Block
|
|
7
7
|
from ailment.expression import Const, VirtualVariable, VirtualVariableCategory, StackBaseOffset
|
|
8
|
-
from ailment.statement import Assignment, Store, Return
|
|
8
|
+
from ailment.statement import Assignment, Store, Return, Jump
|
|
9
9
|
|
|
10
10
|
from angr.knowledge_plugins.functions import Function
|
|
11
11
|
from angr.code_location import CodeLocation
|
|
@@ -98,11 +98,15 @@ class SPropagatorAnalysis(Analysis):
|
|
|
98
98
|
# find all vvar uses
|
|
99
99
|
vvar_uselocs = get_vvar_uselocs(blocks.values())
|
|
100
100
|
|
|
101
|
-
# find all ret sites
|
|
101
|
+
# find all ret sites and indirect jump sites
|
|
102
102
|
retsites: set[tuple[int, int | None, int]] = set()
|
|
103
|
+
jumpsites: set[tuple[int, int | None, int]] = set()
|
|
103
104
|
for bb in blocks.values():
|
|
104
|
-
if bb.statements
|
|
105
|
-
|
|
105
|
+
if bb.statements:
|
|
106
|
+
if isinstance(bb.statements[-1], Return):
|
|
107
|
+
retsites.add((bb.addr, bb.idx, len(bb.statements) - 1))
|
|
108
|
+
elif isinstance(bb.statements[-1], Jump):
|
|
109
|
+
jumpsites.add((bb.addr, bb.idx, len(bb.statements) - 1))
|
|
106
110
|
|
|
107
111
|
replacements = defaultdict(dict)
|
|
108
112
|
|
|
@@ -169,13 +173,13 @@ class SPropagatorAnalysis(Analysis):
|
|
|
169
173
|
{
|
|
170
174
|
loc
|
|
171
175
|
for _, loc in vvar_uselocs[vvar.varid]
|
|
172
|
-
if (loc.block_addr, loc.block_idx, loc.stmt_idx) not in retsites
|
|
176
|
+
if (loc.block_addr, loc.block_idx, loc.stmt_idx) not in (retsites | jumpsites)
|
|
173
177
|
}
|
|
174
178
|
)
|
|
175
179
|
== 1
|
|
176
180
|
):
|
|
177
181
|
if is_const_and_vvar_assignment(stmt):
|
|
178
|
-
# this vvar is used once if we exclude its uses at ret sites. we can propagate it
|
|
182
|
+
# this vvar is used once if we exclude its uses at ret sites or jump sites. we can propagate it
|
|
179
183
|
for vvar_used, vvar_useloc in vvar_uselocs[vvar.varid]:
|
|
180
184
|
replacements[vvar_useloc][vvar_used] = stmt.src
|
|
181
185
|
|
|
@@ -234,15 +238,22 @@ class SPropagatorAnalysis(Analysis):
|
|
|
234
238
|
|
|
235
239
|
if len(tmp_uses) <= 2:
|
|
236
240
|
tmp_used, tmp_use_stmtidx = next(iter(tmp_uses))
|
|
237
|
-
if is_const_vvar_load_dirty_assignment(stmt)
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
|
246
257
|
|
|
247
258
|
self.model.replacements = replacements
|
|
248
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/calling_conventions.py
CHANGED
|
@@ -1212,7 +1212,7 @@ class SimCCCdecl(SimCC):
|
|
|
1212
1212
|
if isinstance(arg_type, (SimTypeArray, SimTypeFixedSizeArray)): # hack
|
|
1213
1213
|
arg_type = SimTypePointer(arg_type.elem_type).with_arch(self.arch)
|
|
1214
1214
|
locs_size = 0
|
|
1215
|
-
byte_size = arg_type.size // self.arch.byte_width
|
|
1215
|
+
byte_size = arg_type.size // self.arch.byte_width if arg_type.size is not None else self.arch.bytes
|
|
1216
1216
|
locs = []
|
|
1217
1217
|
while locs_size < byte_size:
|
|
1218
1218
|
locs.append(next(session.both_iter))
|
|
@@ -1293,7 +1293,7 @@ class SimCCMicrosoftAMD64(SimCC):
|
|
|
1293
1293
|
except StopIteration:
|
|
1294
1294
|
int_loc = fp_loc = next(session.both_iter)
|
|
1295
1295
|
|
|
1296
|
-
byte_size = arg_type.size // self.arch.byte_width
|
|
1296
|
+
byte_size = arg_type.size // self.arch.byte_width if arg_type.size is not None else self.arch.bytes
|
|
1297
1297
|
|
|
1298
1298
|
if isinstance(arg_type, SimTypeFloat):
|
|
1299
1299
|
return fp_loc.refine(size=byte_size, is_fp=True, arch=self.arch)
|
angr/engines/light/engine.py
CHANGED
|
@@ -604,6 +604,9 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
|
|
|
604
604
|
if self._is_top(expr_0) or self._is_top(expr_1):
|
|
605
605
|
return self._top(expr.result_size(self.tyenv))
|
|
606
606
|
|
|
607
|
+
if expr_1.concrete and expr_1.concrete_value == 0:
|
|
608
|
+
return self._top(expr.result_size(self.tyenv))
|
|
609
|
+
|
|
607
610
|
signed = "U" in expr.op # Iop_DivModU64to32 vs Iop_DivMod
|
|
608
611
|
from_size = expr_0.size()
|
|
609
612
|
to_size = expr_1.size()
|
|
@@ -632,10 +635,13 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
|
|
|
632
635
|
if self._is_top(expr_0) or self._is_top(expr_1):
|
|
633
636
|
return self._top(expr_0.size())
|
|
634
637
|
|
|
638
|
+
if expr_1.concrete and expr_1.concrete_value == 0:
|
|
639
|
+
return self._top(expr.result_size(self.tyenv))
|
|
640
|
+
|
|
635
641
|
try:
|
|
636
642
|
return expr_0 / expr_1
|
|
637
643
|
except ZeroDivisionError:
|
|
638
|
-
return self._top(
|
|
644
|
+
return self._top(expr.result_size(self.tyenv))
|
|
639
645
|
|
|
640
646
|
def _handle_Mod(self, expr):
|
|
641
647
|
args, r = self._binop_get_args(expr)
|
|
@@ -646,6 +652,9 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
|
|
|
646
652
|
if self._is_top(expr_0) or self._is_top(expr_1):
|
|
647
653
|
return self._top(expr_0.size())
|
|
648
654
|
|
|
655
|
+
if expr_1.concrete and expr_1.concrete_value == 0:
|
|
656
|
+
return self._top(expr.result_size(self.tyenv))
|
|
657
|
+
|
|
649
658
|
try:
|
|
650
659
|
return expr_0 - (expr_1 // expr_1) * expr_1
|
|
651
660
|
except ZeroDivisionError:
|
|
@@ -948,6 +957,9 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
|
|
|
948
957
|
def _ail_handle_Return(self, stmt):
|
|
949
958
|
pass
|
|
950
959
|
|
|
960
|
+
def _ail_handle_DirtyStatement(self, stmt):
|
|
961
|
+
self._expr(stmt.dirty)
|
|
962
|
+
|
|
951
963
|
#
|
|
952
964
|
# Expression handlers
|
|
953
965
|
#
|
|
@@ -974,7 +986,8 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
|
|
|
974
986
|
return expr
|
|
975
987
|
|
|
976
988
|
def _ail_handle_CallExpr(self, expr: ailment.Stmt.Call):
|
|
977
|
-
|
|
989
|
+
if not isinstance(expr.target, str):
|
|
990
|
+
self._expr(expr.target)
|
|
978
991
|
return expr
|
|
979
992
|
|
|
980
993
|
def _ail_handle_Reinterpret(self, expr: ailment.Expr.Reinterpret):
|
|
@@ -999,6 +1012,15 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
|
|
|
999
1012
|
|
|
1000
1013
|
return expr
|
|
1001
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
|
+
|
|
1002
1024
|
def _ail_handle_UnaryOp(self, expr):
|
|
1003
1025
|
handler_name = f"_handle_{expr.op}"
|
|
1004
1026
|
try:
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
import logging
|
|
3
4
|
|
|
5
|
+
import claripy
|
|
6
|
+
|
|
4
7
|
from .base import SimSootExpr
|
|
5
8
|
|
|
6
9
|
l = logging.getLogger(name=__name__)
|
|
@@ -9,4 +12,4 @@ l = logging.getLogger(name=__name__)
|
|
|
9
12
|
class SimSootExpr_InstanceOf(SimSootExpr):
|
|
10
13
|
def _execute(self):
|
|
11
14
|
obj = self._translate_value(self.expr.value)
|
|
12
|
-
self.expr =
|
|
15
|
+
self.expr = claripy.StringV(obj.type) == claripy.StringV(self.expr.check_type)
|
angr/engines/successors.py
CHANGED
|
@@ -504,7 +504,7 @@ class SimSuccessors:
|
|
|
504
504
|
fallback = True
|
|
505
505
|
break
|
|
506
506
|
|
|
507
|
-
cond_and_targets.append((cond, target if not outer_reverse else
|
|
507
|
+
cond_and_targets.append((cond, target if not outer_reverse else claripy.Reverse(target)))
|
|
508
508
|
|
|
509
509
|
if reached_sentinel is False:
|
|
510
510
|
# huh?
|