angr 9.2.147__py3-none-win_amd64.whl → 9.2.149__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/analysis.py +3 -11
- angr/analyses/calling_convention/calling_convention.py +42 -2
- angr/analyses/calling_convention/fact_collector.py +5 -4
- angr/analyses/calling_convention/utils.py +1 -0
- angr/analyses/cfg/cfg_base.py +3 -59
- angr/analyses/cfg/cfg_emulated.py +17 -14
- angr/analyses/cfg/cfg_fast.py +68 -63
- angr/analyses/cfg/cfg_fast_soot.py +3 -3
- angr/analyses/decompiler/ail_simplifier.py +65 -32
- angr/analyses/decompiler/block_simplifier.py +20 -6
- angr/analyses/decompiler/callsite_maker.py +28 -18
- angr/analyses/decompiler/clinic.py +84 -17
- angr/analyses/decompiler/condition_processor.py +0 -21
- angr/analyses/decompiler/counters/call_counter.py +3 -0
- angr/analyses/decompiler/dephication/rewriting_engine.py +24 -2
- angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
- angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +15 -13
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +1 -1
- angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
- angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +165 -0
- angr/analyses/decompiler/optimization_passes/engine_base.py +11 -2
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +17 -2
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +10 -6
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +99 -30
- angr/analyses/decompiler/peephole_optimizations/__init__.py +6 -0
- angr/analyses/decompiler/peephole_optimizations/base.py +43 -3
- angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +3 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +4 -1
- angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +69 -2
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +14 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
- angr/analyses/decompiler/presets/fast.py +2 -0
- angr/analyses/decompiler/presets/full.py +2 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +51 -4
- angr/analyses/decompiler/ssailification/ssailification.py +23 -3
- angr/analyses/decompiler/ssailification/traversal_engine.py +15 -1
- angr/analyses/decompiler/structured_codegen/c.py +146 -15
- angr/analyses/decompiler/structuring/phoenix.py +11 -3
- angr/analyses/decompiler/utils.py +6 -1
- angr/analyses/deobfuscator/api_obf_finder.py +5 -1
- angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
- angr/analyses/forward_analysis/visitors/graph.py +0 -8
- angr/analyses/identifier/runner.py +1 -1
- angr/analyses/reaching_definitions/function_handler.py +4 -4
- angr/analyses/reassembler.py +1 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +1 -0
- angr/analyses/stack_pointer_tracker.py +1 -1
- angr/analyses/static_hooker.py +11 -9
- angr/analyses/typehoon/lifter.py +20 -0
- angr/analyses/typehoon/simple_solver.py +42 -9
- angr/analyses/typehoon/translator.py +4 -1
- angr/analyses/typehoon/typeconsts.py +17 -6
- angr/analyses/typehoon/typehoon.py +21 -5
- angr/analyses/variable_recovery/engine_ail.py +52 -13
- angr/analyses/variable_recovery/engine_base.py +37 -12
- angr/analyses/variable_recovery/variable_recovery_fast.py +33 -2
- angr/calling_conventions.py +96 -27
- angr/engines/light/engine.py +7 -0
- angr/exploration_techniques/director.py +1 -1
- angr/knowledge_plugins/functions/function.py +109 -38
- angr/knowledge_plugins/functions/function_manager.py +9 -0
- angr/knowledge_plugins/functions/function_parser.py +9 -1
- angr/knowledge_plugins/functions/soot_function.py +1 -1
- angr/knowledge_plugins/key_definitions/key_definition_manager.py +1 -1
- angr/knowledge_plugins/propagations/states.py +5 -2
- angr/knowledge_plugins/variables/variable_manager.py +3 -3
- angr/lib/angr_native.dll +0 -0
- angr/procedures/definitions/__init__.py +15 -12
- angr/procedures/definitions/types_stl.py +22 -0
- angr/procedures/stubs/format_parser.py +1 -1
- angr/project.py +23 -29
- angr/protos/cfg_pb2.py +14 -25
- angr/protos/function_pb2.py +11 -22
- angr/protos/primitives_pb2.py +36 -47
- angr/protos/variables_pb2.py +28 -39
- angr/protos/xrefs_pb2.py +8 -19
- angr/sim_type.py +251 -146
- angr/simos/cgc.py +1 -1
- angr/simos/linux.py +5 -5
- angr/simos/windows.py +5 -5
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -1
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/METADATA +9 -8
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/RECORD +91 -85
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/WHEEL +1 -1
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info/licenses}/LICENSE +3 -0
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/entry_points.txt +0 -0
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
from typing import TYPE_CHECKING
|
|
3
3
|
|
|
4
4
|
from ailment import Block
|
|
5
|
+
from ailment.statement import Label
|
|
5
6
|
from ailment.block_walker import AILBlockWalkerBase
|
|
6
7
|
|
|
7
8
|
from angr.analyses.decompiler.sequence_walker import SequenceWalker
|
|
@@ -37,8 +38,10 @@ class AILCallCounter(SequenceWalker):
|
|
|
37
38
|
}
|
|
38
39
|
super().__init__(handlers)
|
|
39
40
|
self.calls = 0
|
|
41
|
+
self.non_label_stmts = 0
|
|
40
42
|
|
|
41
43
|
def _handle_Block(self, node: Block, **kwargs): # pylint:disable=unused-argument
|
|
42
44
|
ctr = AILBlockCallCounter()
|
|
43
45
|
ctr.walk(node)
|
|
44
46
|
self.calls += ctr.calls
|
|
47
|
+
self.non_label_stmts += sum(1 for stmt in node.statements if not isinstance(stmt, Label))
|
|
@@ -3,7 +3,16 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
from ailment.block import Block
|
|
6
|
-
from ailment.statement import
|
|
6
|
+
from ailment.statement import (
|
|
7
|
+
Statement,
|
|
8
|
+
Assignment,
|
|
9
|
+
Store,
|
|
10
|
+
Call,
|
|
11
|
+
Return,
|
|
12
|
+
ConditionalJump,
|
|
13
|
+
DirtyStatement,
|
|
14
|
+
WeakAssignment,
|
|
15
|
+
)
|
|
7
16
|
from ailment.expression import (
|
|
8
17
|
Expression,
|
|
9
18
|
VirtualVariable,
|
|
@@ -99,6 +108,19 @@ class SimEngineDephiRewriting(SimEngineNostmtAIL[None, Expression | None, Statem
|
|
|
99
108
|
return Assignment(stmt.idx, dst, src, **stmt.tags)
|
|
100
109
|
return None
|
|
101
110
|
|
|
111
|
+
def _handle_stmt_WeakAssignment(self, stmt) -> WeakAssignment | None:
|
|
112
|
+
new_src = self._expr(stmt.src)
|
|
113
|
+
new_dst = self._expr(stmt.dst)
|
|
114
|
+
|
|
115
|
+
if new_dst is not None or new_src is not None:
|
|
116
|
+
return WeakAssignment(
|
|
117
|
+
stmt.idx,
|
|
118
|
+
stmt.dst if new_dst is None else new_dst, # type: ignore
|
|
119
|
+
stmt.src if new_src is None else new_src,
|
|
120
|
+
**stmt.tags,
|
|
121
|
+
)
|
|
122
|
+
return None
|
|
123
|
+
|
|
102
124
|
def _handle_stmt_Store(self, stmt):
|
|
103
125
|
new_addr = self._expr(stmt.addr)
|
|
104
126
|
new_data = self._expr(stmt.data)
|
|
@@ -299,7 +321,7 @@ class SimEngineDephiRewriting(SimEngineNostmtAIL[None, Expression | None, Statem
|
|
|
299
321
|
return VEXCCallExpression(
|
|
300
322
|
expr.idx,
|
|
301
323
|
expr.callee,
|
|
302
|
-
new_operands,
|
|
324
|
+
tuple(new_operands),
|
|
303
325
|
bits=expr.bits,
|
|
304
326
|
**expr.tags,
|
|
305
327
|
)
|
|
@@ -33,6 +33,8 @@ from .call_stmt_rewriter import CallStatementRewriter
|
|
|
33
33
|
from .duplication_reverter import DuplicationReverter
|
|
34
34
|
from .switch_reused_entry_rewriter import SwitchReusedEntryRewriter
|
|
35
35
|
from .condition_constprop import ConditionConstantPropagation
|
|
36
|
+
from .determine_load_sizes import DetermineLoadSizes
|
|
37
|
+
from .eager_std_string_concatenation import EagerStdStringConcatenationPass
|
|
36
38
|
|
|
37
39
|
if TYPE_CHECKING:
|
|
38
40
|
from angr.analyses.decompiler.presets import DecompilationPreset
|
|
@@ -68,6 +70,8 @@ ALL_OPTIMIZATION_PASSES = [
|
|
|
68
70
|
CallStatementRewriter,
|
|
69
71
|
TagSlicer,
|
|
70
72
|
ConditionConstantPropagation,
|
|
73
|
+
DetermineLoadSizes,
|
|
74
|
+
EagerStdStringConcatenationPass,
|
|
71
75
|
]
|
|
72
76
|
|
|
73
77
|
# these passes may duplicate code to remove gotos or improve the structure of the graph
|
|
@@ -122,6 +126,7 @@ __all__ = (
|
|
|
122
126
|
"DeadblockRemover",
|
|
123
127
|
"DivSimplifier",
|
|
124
128
|
"DuplicationReverter",
|
|
129
|
+
"EagerStdStringConcatenationPass",
|
|
125
130
|
"ExprOpSwapper",
|
|
126
131
|
"FlipBooleanCmp",
|
|
127
132
|
"ITEExprConverter",
|
|
@@ -98,20 +98,22 @@ class BasePointerSaveSimplifier(OptimizationPass):
|
|
|
98
98
|
and isinstance(stmt.dst, ailment.Expr.VirtualVariable)
|
|
99
99
|
and stmt.dst.was_stack
|
|
100
100
|
and stmt.dst.stack_offset < 0
|
|
101
|
-
and isinstance(stmt.src, ailment.Expr.VirtualVariable)
|
|
102
|
-
and stmt.src.was_reg
|
|
103
|
-
and stmt.src.reg_offset == self.project.arch.bp_offset
|
|
104
101
|
):
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
102
|
+
if (
|
|
103
|
+
isinstance(stmt.src, ailment.Expr.VirtualVariable)
|
|
104
|
+
and stmt.src.was_reg
|
|
105
|
+
and stmt.src.reg_offset == self.project.arch.bp_offset
|
|
106
|
+
):
|
|
107
|
+
return first_block, idx, stmt.dst
|
|
108
|
+
if isinstance(stmt.src, ailment.Expr.StackBaseOffset) and stmt.src.offset == 0:
|
|
109
|
+
return first_block, idx, stmt.dst
|
|
110
|
+
if (
|
|
111
|
+
isinstance(stmt.src, ailment.Expr.UnaryOp)
|
|
112
|
+
and isinstance(stmt.src.operand, ailment.Expr.VirtualVariable)
|
|
113
|
+
and stmt.src.operand.was_stack
|
|
114
|
+
and stmt.src.operand.stack_offset == 0
|
|
115
|
+
):
|
|
116
|
+
return first_block, idx, stmt.dst
|
|
115
117
|
|
|
116
118
|
# Not found
|
|
117
119
|
return None
|
|
@@ -66,7 +66,7 @@ class PairAILBlockWalker:
|
|
|
66
66
|
def _handle_call_expr(expr_idx: int, expr: Call, stmt_idx: int, stmt: Statement, block_):
|
|
67
67
|
walked_objs[Call].add(expr)
|
|
68
68
|
|
|
69
|
-
_stmt_handlers =
|
|
69
|
+
_stmt_handlers = dict.fromkeys(walked_objs, _handle_ail_obj)
|
|
70
70
|
walker.stmt_handlers = _stmt_handlers
|
|
71
71
|
walker.expr_handlers[Call] = _handle_call_expr
|
|
72
72
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from ailment.constant import UNDETERMINED_SIZE
|
|
5
|
+
from ailment.expression import BinaryOp, Load, Const
|
|
6
|
+
from ailment.statement import Assignment, WeakAssignment
|
|
7
|
+
|
|
8
|
+
from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
_l = logging.getLogger(name=__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DetermineLoadSizes(OptimizationPass):
|
|
15
|
+
"""
|
|
16
|
+
Determine the sizes of Load expressions whose sizes are undetermined.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
ARCHES = None
|
|
20
|
+
PLATFORMS = None
|
|
21
|
+
STAGE = OptimizationPassStage.AFTER_GLOBAL_SIMPLIFICATION
|
|
22
|
+
NAME = "Determine sizes of loads whose sizes are undetermined"
|
|
23
|
+
DESCRIPTION = __doc__.strip() # type: ignore
|
|
24
|
+
|
|
25
|
+
def __init__(self, func, **kwargs):
|
|
26
|
+
super().__init__(func, **kwargs)
|
|
27
|
+
|
|
28
|
+
self.analyze()
|
|
29
|
+
|
|
30
|
+
def _check(self):
|
|
31
|
+
return True, None
|
|
32
|
+
|
|
33
|
+
def _analyze(self, cache=None):
|
|
34
|
+
|
|
35
|
+
changed = False
|
|
36
|
+
|
|
37
|
+
for block in self._graph.nodes:
|
|
38
|
+
for idx in range(len(block.statements)): # pylint:disable=consider-using-enumerate
|
|
39
|
+
stmt = block.statements[idx]
|
|
40
|
+
if isinstance(stmt, (Assignment, WeakAssignment)):
|
|
41
|
+
if isinstance(stmt.src, BinaryOp) and stmt.src.op == "Add" and stmt.src.operands:
|
|
42
|
+
operands = stmt.src.operands
|
|
43
|
+
elif isinstance(stmt.src, Load):
|
|
44
|
+
operands = [stmt.src]
|
|
45
|
+
else:
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
for operand in operands:
|
|
49
|
+
if (
|
|
50
|
+
isinstance(operand, Load)
|
|
51
|
+
and isinstance(operand.addr, Const)
|
|
52
|
+
and operand.size == UNDETERMINED_SIZE
|
|
53
|
+
):
|
|
54
|
+
# probably a string!
|
|
55
|
+
bs = self.project.loader.memory.load_null_terminated_bytes(
|
|
56
|
+
operand.addr.value, max_size=4096
|
|
57
|
+
)
|
|
58
|
+
if bs is not None:
|
|
59
|
+
operand.size = len(bs)
|
|
60
|
+
operand.bits = len(bs) * 8
|
|
61
|
+
changed = True
|
|
62
|
+
|
|
63
|
+
if changed:
|
|
64
|
+
self.out_graph = self._graph
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# pylint:disable=too-many-boolean-expressions,unused-argument
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
import logging
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from archinfo import Endness
|
|
8
|
+
|
|
9
|
+
from ailment.constant import UNDETERMINED_SIZE
|
|
10
|
+
from ailment.statement import Assignment, WeakAssignment
|
|
11
|
+
from ailment.expression import VirtualVariable, BinaryOp, Const, Load
|
|
12
|
+
|
|
13
|
+
from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from angr.analyses.s_reaching_definitions import SRDAModel
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_l = logging.getLogger(name=__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class EagerStdStringConcatenationPass(OptimizationPass):
|
|
23
|
+
"""
|
|
24
|
+
TODO: Unfinished
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
ARCHES = None
|
|
28
|
+
PLATFORMS = None
|
|
29
|
+
STAGE = OptimizationPassStage.BEFORE_VARIABLE_RECOVERY
|
|
30
|
+
NAME = "Condense multiple constant std::string creation calls into one when possible"
|
|
31
|
+
DESCRIPTION = __doc__.strip() # type: ignore
|
|
32
|
+
|
|
33
|
+
def __init__(self, func, **kwargs):
|
|
34
|
+
super().__init__(func, **kwargs)
|
|
35
|
+
self.analyze()
|
|
36
|
+
|
|
37
|
+
def _check(self):
|
|
38
|
+
# TODO: ensure func calls std::string::operator+ and std::string::operator=
|
|
39
|
+
return False, {}
|
|
40
|
+
|
|
41
|
+
def _analyze(self, cache=None):
|
|
42
|
+
rd = self.project.analyses.SReachingDefinitions(subject=self._func, func_graph=self._graph).model
|
|
43
|
+
cfg = self.kb.cfgs.get_most_accurate()
|
|
44
|
+
assert cfg is not None
|
|
45
|
+
|
|
46
|
+
# update each block
|
|
47
|
+
for key in list(self.blocks_by_addr_and_idx):
|
|
48
|
+
block = self.blocks_by_addr_and_idx[key]
|
|
49
|
+
new_block = None
|
|
50
|
+
for idx, stmt in enumerate(block.statements):
|
|
51
|
+
if (
|
|
52
|
+
isinstance(stmt, Assignment)
|
|
53
|
+
and hasattr(stmt, "type")
|
|
54
|
+
and "dst" in stmt.type
|
|
55
|
+
and "src" in stmt.type
|
|
56
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
57
|
+
and isinstance(stmt.src, BinaryOp)
|
|
58
|
+
and stmt.src.op == "Add"
|
|
59
|
+
):
|
|
60
|
+
dst_ty, src_ty = stmt.type["dst"], stmt.type["src"]
|
|
61
|
+
if self._is_std_string_type(dst_ty.c_repr()) and self._is_std_string_type(src_ty.c_repr()):
|
|
62
|
+
op0, op1 = stmt.src.operands
|
|
63
|
+
if isinstance(op1, VirtualVariable) and isinstance(op0, Load):
|
|
64
|
+
op0, op1 = op1, op0
|
|
65
|
+
if (
|
|
66
|
+
isinstance(op0, VirtualVariable)
|
|
67
|
+
and isinstance(op1, Load)
|
|
68
|
+
and isinstance(op1.addr, Const)
|
|
69
|
+
and isinstance(op1.addr.value, int)
|
|
70
|
+
# is op1 a constant string?
|
|
71
|
+
and op1.addr.value in cfg.memory_data
|
|
72
|
+
and cfg.memory_data[op1.addr.value].sort == "string"
|
|
73
|
+
):
|
|
74
|
+
op1_str = cfg.memory_data[op1.addr.value].content
|
|
75
|
+
# is op0 also an std::string?
|
|
76
|
+
op0_str = self._get_vvar_def_string(op0.varid, rd, cfg, block.addr, block.idx)
|
|
77
|
+
if op0_str is not None and op1_str is not None:
|
|
78
|
+
# let's create a new string
|
|
79
|
+
final_str = op0_str + op1_str
|
|
80
|
+
str_id = self.kb.custom_strings.allocate(final_str)
|
|
81
|
+
# replace the assignment with a new assignment
|
|
82
|
+
new_stmt = WeakAssignment(
|
|
83
|
+
stmt.idx,
|
|
84
|
+
stmt.dst,
|
|
85
|
+
Load(
|
|
86
|
+
None,
|
|
87
|
+
Const(None, None, str_id, self.project.arch.bits, custom_string=True),
|
|
88
|
+
UNDETERMINED_SIZE,
|
|
89
|
+
Endness.BE,
|
|
90
|
+
),
|
|
91
|
+
**stmt.tags,
|
|
92
|
+
)
|
|
93
|
+
new_block = block.copy() if new_block is None else new_block
|
|
94
|
+
new_block.statements[idx] = new_stmt
|
|
95
|
+
if new_block is not None:
|
|
96
|
+
self._update_block(block, new_block)
|
|
97
|
+
|
|
98
|
+
def _get_vvar_def_string(self, vvar_id: int, rd: SRDAModel, cfg, block_addr, block_idx) -> bytes | None:
|
|
99
|
+
# search for the closest weak definition of the specified variable
|
|
100
|
+
# TODO: Optimize this logic in the future
|
|
101
|
+
|
|
102
|
+
starting_block = self.blocks_by_addr_and_idx[(block_addr, block_idx)]
|
|
103
|
+
queue = [starting_block]
|
|
104
|
+
visited = set()
|
|
105
|
+
while queue:
|
|
106
|
+
block = queue.pop(0)
|
|
107
|
+
if block in visited:
|
|
108
|
+
continue
|
|
109
|
+
visited.add(block)
|
|
110
|
+
|
|
111
|
+
if not (block.addr == block_addr and block.idx == block_idx):
|
|
112
|
+
for stmt in block.statements:
|
|
113
|
+
if (
|
|
114
|
+
isinstance(stmt, WeakAssignment)
|
|
115
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
116
|
+
and stmt.dst.varid == vvar_id
|
|
117
|
+
):
|
|
118
|
+
if (
|
|
119
|
+
isinstance(stmt.src, Load)
|
|
120
|
+
and isinstance(stmt.src.addr, Const)
|
|
121
|
+
and stmt.src.addr.value in cfg.memory_data
|
|
122
|
+
):
|
|
123
|
+
if cfg.memory_data[stmt.src.addr.value].sort == "string":
|
|
124
|
+
return cfg.memory_data[stmt.src.addr.value].content
|
|
125
|
+
elif (
|
|
126
|
+
isinstance(stmt.src, Const)
|
|
127
|
+
and hasattr(stmt.src, "custom_string")
|
|
128
|
+
and stmt.src.custom_string
|
|
129
|
+
):
|
|
130
|
+
return self.kb.custom_strings.get(stmt.src.value)
|
|
131
|
+
|
|
132
|
+
preds = list(self._graph.predecessors(block))
|
|
133
|
+
if len(preds) == 1:
|
|
134
|
+
queue.append(preds[0])
|
|
135
|
+
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def _is_std_string_type(type_str: str) -> bool:
|
|
140
|
+
type_str = type_str.removeprefix("const ")
|
|
141
|
+
return (
|
|
142
|
+
re.match(
|
|
143
|
+
r"class std::basic_string<char a\d+, struct std::char_traits<char> a\d+, class std::allocator<char>>",
|
|
144
|
+
type_str,
|
|
145
|
+
)
|
|
146
|
+
is not None
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# pcreg_offset = self.project.arch.registers[getpc_reg][0]
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
#
|
|
153
|
+
# old_block = self.blocks_by_addr_and_idx[block_key]
|
|
154
|
+
# block = old_block.copy()
|
|
155
|
+
# old_stmt = block.statements[stmt_idx]
|
|
156
|
+
# block.statements[stmt_idx] = ailment.Stmt.Assignment(
|
|
157
|
+
# old_stmt.idx,
|
|
158
|
+
# ailment.Expr.Register(None, None, pcreg_offset, 32, reg_name=getpc_reg),
|
|
159
|
+
# ailment.Expr.Const(None, None, getpc_reg_value, 32),
|
|
160
|
+
# **old_stmt.tags,
|
|
161
|
+
# )
|
|
162
|
+
# # remove the statement that pushes return address onto the stack
|
|
163
|
+
# if stmt_idx > 0 and isinstance(block.statements[stmt_idx - 1], ailment.Stmt.Store):
|
|
164
|
+
# block.statements = block.statements[: stmt_idx - 1] + block.statements[stmt_idx:]
|
|
165
|
+
# self._update_block(old_block, block)
|
|
@@ -73,7 +73,16 @@ class SimplifierAILEngine(
|
|
|
73
73
|
self.state.store_variable(dst, src)
|
|
74
74
|
|
|
75
75
|
if (src, dst) != (stmt.src, stmt.dst):
|
|
76
|
-
return ailment.statement.Assignment(stmt.idx, dst, src, **stmt.tags)
|
|
76
|
+
return ailment.statement.Assignment(stmt.idx, dst, src, **stmt.tags) # type:ignore
|
|
77
|
+
|
|
78
|
+
return stmt
|
|
79
|
+
|
|
80
|
+
def _handle_stmt_WeakAssignment(self, stmt: ailment.statement.WeakAssignment):
|
|
81
|
+
src = self._expr(stmt.src)
|
|
82
|
+
dst = self._expr(stmt.dst)
|
|
83
|
+
|
|
84
|
+
if (src, dst) != (stmt.src, stmt.dst):
|
|
85
|
+
return ailment.statement.WeakAssignment(stmt.idx, dst, src, **stmt.tags) # type:ignore
|
|
77
86
|
|
|
78
87
|
return stmt
|
|
79
88
|
|
|
@@ -150,7 +159,7 @@ class SimplifierAILEngine(
|
|
|
150
159
|
def _handle_stmt_DirtyStatement(self, stmt):
|
|
151
160
|
expr = self._expr(stmt.dirty)
|
|
152
161
|
if expr != stmt.dirty:
|
|
153
|
-
return ailment.statement.DirtyStatement(stmt.idx, expr, **stmt.tags)
|
|
162
|
+
return ailment.statement.DirtyStatement(stmt.idx, expr, **stmt.tags) # type:ignore
|
|
154
163
|
return stmt
|
|
155
164
|
|
|
156
165
|
def _handle_stmt_Label(self, stmt):
|
|
@@ -161,13 +161,28 @@ class InlinedStringTransformationAILEngine(
|
|
|
161
161
|
return addr.value, "mem"
|
|
162
162
|
if isinstance(addr, StackBaseOffset):
|
|
163
163
|
return (addr.offset + self.STACK_BASE) & self.MASK, "stack"
|
|
164
|
-
if
|
|
164
|
+
if (
|
|
165
|
+
isinstance(addr, UnaryOp)
|
|
166
|
+
and addr.op == "Reference"
|
|
167
|
+
and isinstance(addr.operand, VirtualVariable)
|
|
168
|
+
and addr.operand.was_stack
|
|
169
|
+
):
|
|
170
|
+
return (addr.operand.stack_offset + self.STACK_BASE) & self.MASK, "stack"
|
|
171
|
+
if (
|
|
172
|
+
isinstance(addr, BinaryOp)
|
|
173
|
+
and addr.op in {"Add", "Sub"}
|
|
174
|
+
and isinstance(addr.operands[0], (StackBaseOffset, UnaryOp, Const))
|
|
175
|
+
):
|
|
165
176
|
v0_and_type = self._process_address(addr.operands[0])
|
|
166
177
|
if v0_and_type is not None:
|
|
167
178
|
v0 = v0_and_type[0]
|
|
168
179
|
v1 = self._expr(addr.operands[1])
|
|
169
180
|
if isinstance(v1, claripy.ast.Bits) and v1.concrete:
|
|
170
|
-
|
|
181
|
+
if addr.op == "Add":
|
|
182
|
+
return (v0 + v1.concrete_value) & self.MASK, "stack"
|
|
183
|
+
if addr.op == "Sub":
|
|
184
|
+
return (v0 - v1.concrete_value) & self.MASK, "stack"
|
|
185
|
+
raise NotImplementedError("Unreachable")
|
|
171
186
|
return None
|
|
172
187
|
|
|
173
188
|
def _handle_stmt_Assignment(self, stmt):
|
|
@@ -53,12 +53,14 @@ class OptimizationPassStage(Enum):
|
|
|
53
53
|
AFTER_AIL_GRAPH_CREATION = 0
|
|
54
54
|
BEFORE_SSA_LEVEL0_TRANSFORMATION = 1
|
|
55
55
|
AFTER_SINGLE_BLOCK_SIMPLIFICATION = 2
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
BEFORE_SSA_LEVEL1_TRANSFORMATION = 3
|
|
57
|
+
AFTER_MAKING_CALLSITES = 4
|
|
58
|
+
AFTER_GLOBAL_SIMPLIFICATION = 5
|
|
59
|
+
BEFORE_VARIABLE_RECOVERY = 6
|
|
60
|
+
AFTER_VARIABLE_RECOVERY = 7
|
|
61
|
+
BEFORE_REGION_IDENTIFICATION = 8
|
|
62
|
+
DURING_REGION_IDENTIFICATION = 9
|
|
63
|
+
AFTER_STRUCTURING = 10
|
|
62
64
|
|
|
63
65
|
|
|
64
66
|
class BaseOptimizationPass:
|
|
@@ -137,6 +139,7 @@ class OptimizationPass(BaseOptimizationPass):
|
|
|
137
139
|
avoid_vvar_ids: set[int] | None = None,
|
|
138
140
|
arg_vvars: set[int] | None = None,
|
|
139
141
|
peephole_optimizations=None,
|
|
142
|
+
stack_pointer_tracker=None,
|
|
140
143
|
**kwargs,
|
|
141
144
|
):
|
|
142
145
|
super().__init__(func)
|
|
@@ -158,6 +161,7 @@ class OptimizationPass(BaseOptimizationPass):
|
|
|
158
161
|
self._complete_successors = complete_successors
|
|
159
162
|
self._avoid_vvar_ids = avoid_vvar_ids or set()
|
|
160
163
|
self._peephole_optimizations = peephole_optimizations
|
|
164
|
+
self._stack_pointer_tracker = stack_pointer_tracker
|
|
161
165
|
|
|
162
166
|
# output
|
|
163
167
|
self.out_graph: networkx.DiGraph | None = None
|