angr 9.2.130__py3-none-win_amd64.whl → 9.2.132__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 +6 -2
- angr/analyses/cfg/cfg_emulated.py +5 -5
- angr/analyses/cfg/cfg_fast.py +2 -2
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +139 -94
- angr/analyses/cfg/indirect_jump_resolvers/x86_elf_pic_plt.py +1 -1
- angr/analyses/ddg.py +14 -11
- angr/analyses/decompiler/ail_simplifier.py +3 -2
- angr/analyses/decompiler/block_simplifier.py +10 -21
- angr/analyses/decompiler/clinic.py +361 -8
- angr/analyses/decompiler/condition_processor.py +12 -10
- angr/analyses/decompiler/dephication/graph_rewriting.py +1 -1
- angr/analyses/decompiler/dephication/rewriting_engine.py +169 -45
- angr/analyses/decompiler/dephication/seqnode_dephication.py +5 -4
- angr/analyses/decompiler/optimization_passes/__init__.py +0 -3
- angr/analyses/decompiler/optimization_passes/const_derefs.py +1 -0
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +41 -16
- angr/analyses/decompiler/optimization_passes/engine_base.py +261 -83
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +173 -35
- angr/analyses/decompiler/optimization_passes/mod_simplifier.py +5 -2
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +39 -19
- angr/analyses/decompiler/peephole_optimizations/__init__.py +5 -1
- angr/analyses/decompiler/peephole_optimizations/a_mul_const_sub_a.py +34 -0
- angr/analyses/decompiler/peephole_optimizations/a_shl_const_sub_a.py +3 -1
- angr/analyses/decompiler/peephole_optimizations/bswap.py +10 -6
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +100 -19
- angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py +17 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +42 -3
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +4 -2
- angr/analyses/decompiler/peephole_optimizations/rol_ror.py +37 -10
- angr/analyses/decompiler/peephole_optimizations/shl_to_mul.py +25 -0
- angr/analyses/decompiler/peephole_optimizations/utils.py +18 -0
- angr/analyses/decompiler/presets/fast.py +0 -2
- angr/analyses/decompiler/presets/full.py +0 -2
- angr/analyses/decompiler/ssailification/rewriting.py +1 -2
- angr/analyses/decompiler/ssailification/rewriting_engine.py +140 -57
- angr/analyses/decompiler/ssailification/ssailification.py +2 -1
- angr/analyses/decompiler/ssailification/traversal.py +4 -6
- angr/analyses/decompiler/ssailification/traversal_engine.py +125 -42
- angr/analyses/decompiler/structured_codegen/c.py +79 -16
- angr/analyses/decompiler/structuring/phoenix.py +40 -14
- angr/analyses/decompiler/structuring/structurer_nodes.py +9 -0
- angr/analyses/deobfuscator/irsb_reg_collector.py +29 -60
- angr/analyses/deobfuscator/string_obf_finder.py +2 -2
- angr/analyses/init_finder.py +47 -22
- angr/analyses/propagator/engine_base.py +21 -14
- angr/analyses/propagator/engine_vex.py +149 -179
- angr/analyses/propagator/propagator.py +10 -28
- angr/analyses/propagator/top_checker_mixin.py +211 -5
- angr/analyses/propagator/vex_vars.py +1 -1
- angr/analyses/reaching_definitions/dep_graph.py +1 -1
- angr/analyses/reaching_definitions/engine_ail.py +304 -329
- angr/analyses/reaching_definitions/engine_vex.py +243 -229
- angr/analyses/reaching_definitions/function_handler.py +3 -3
- angr/analyses/reaching_definitions/rd_state.py +37 -32
- angr/analyses/s_propagator.py +38 -5
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +9 -5
- angr/analyses/typehoon/simple_solver.py +16 -7
- angr/analyses/typehoon/translator.py +8 -0
- angr/analyses/typehoon/typeconsts.py +10 -2
- angr/analyses/typehoon/typehoon.py +4 -1
- angr/analyses/typehoon/typevars.py +9 -7
- angr/analyses/variable_recovery/engine_ail.py +296 -256
- angr/analyses/variable_recovery/engine_base.py +137 -116
- angr/analyses/variable_recovery/engine_vex.py +175 -185
- angr/analyses/variable_recovery/irsb_scanner.py +49 -38
- angr/analyses/variable_recovery/variable_recovery.py +28 -5
- angr/analyses/variable_recovery/variable_recovery_base.py +32 -33
- angr/analyses/variable_recovery/variable_recovery_fast.py +2 -2
- angr/analyses/xrefs.py +46 -19
- angr/annocfg.py +19 -14
- angr/block.py +4 -9
- angr/calling_conventions.py +1 -1
- angr/engines/engine.py +30 -14
- angr/engines/light/__init__.py +11 -3
- angr/engines/light/engine.py +1003 -1185
- angr/engines/pcode/cc.py +2 -0
- angr/engines/successors.py +13 -9
- angr/engines/vex/claripy/datalayer.py +1 -1
- angr/engines/vex/claripy/irop.py +14 -3
- angr/engines/vex/light/slicing.py +2 -2
- angr/exploration_techniques/__init__.py +1 -124
- angr/exploration_techniques/base.py +126 -0
- angr/exploration_techniques/bucketizer.py +1 -1
- angr/exploration_techniques/dfs.py +3 -1
- angr/exploration_techniques/director.py +2 -3
- angr/exploration_techniques/driller_core.py +1 -1
- angr/exploration_techniques/explorer.py +4 -2
- angr/exploration_techniques/lengthlimiter.py +2 -1
- angr/exploration_techniques/local_loop_seer.py +2 -1
- angr/exploration_techniques/loop_seer.py +5 -5
- angr/exploration_techniques/manual_mergepoint.py +2 -1
- angr/exploration_techniques/memory_watcher.py +3 -1
- angr/exploration_techniques/oppologist.py +4 -5
- angr/exploration_techniques/slicecutor.py +4 -2
- angr/exploration_techniques/spiller.py +1 -1
- angr/exploration_techniques/stochastic.py +2 -1
- angr/exploration_techniques/stub_stasher.py +2 -1
- angr/exploration_techniques/suggestions.py +3 -1
- angr/exploration_techniques/symbion.py +3 -1
- angr/exploration_techniques/tech_builder.py +2 -1
- angr/exploration_techniques/threading.py +4 -7
- angr/exploration_techniques/timeout.py +4 -2
- angr/exploration_techniques/tracer.py +4 -3
- angr/exploration_techniques/unique.py +3 -2
- angr/exploration_techniques/veritesting.py +1 -1
- angr/knowledge_plugins/key_definitions/atoms.py +2 -2
- angr/knowledge_plugins/key_definitions/live_definitions.py +16 -13
- angr/knowledge_plugins/propagations/states.py +13 -8
- angr/knowledge_plugins/variables/variable_manager.py +23 -9
- angr/lib/angr_native.dll +0 -0
- angr/sim_manager.py +1 -3
- angr/sim_state.py +39 -41
- angr/sim_type.py +5 -0
- angr/sim_variable.py +29 -28
- angr/utils/bits.py +17 -0
- angr/utils/formatting.py +4 -1
- angr/utils/orderedset.py +4 -1
- angr/utils/ssa/__init__.py +21 -3
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/METADATA +6 -6
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/RECORD +125 -124
- angr/analyses/decompiler/optimization_passes/multi_simplifier.py +0 -223
- angr/analyses/propagator/engine_ail.py +0 -1562
- angr/storage/memory_mixins/__init__.pyi +0 -48
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/LICENSE +0 -0
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/WHEEL +0 -0
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/entry_points.txt +0 -0
- {angr-9.2.130.dist-info → angr-9.2.132.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
# pylint:disable=missing-class-docstring,no-self-use
|
|
1
2
|
from __future__ import annotations
|
|
2
3
|
from ailment.expression import BinaryOp, Const, Expression, Convert
|
|
3
4
|
from ailment.statement import Call
|
|
4
5
|
|
|
5
6
|
from .base import PeepholeOptimizationExprBase
|
|
7
|
+
from .utils import get_expr_shift_left_amount
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class Bswap(PeepholeOptimizationExprBase):
|
|
@@ -69,19 +71,21 @@ class Bswap(PeepholeOptimizationExprBase):
|
|
|
69
71
|
cores = set()
|
|
70
72
|
for piece in or_pieces:
|
|
71
73
|
if isinstance(piece, BinaryOp):
|
|
72
|
-
if piece.op
|
|
74
|
+
if piece.op in {"Shl", "Mul"} and isinstance(piece.operands[1], Const):
|
|
73
75
|
cores.add(piece.operands[0])
|
|
74
|
-
|
|
76
|
+
shift_amount = get_expr_shift_left_amount(piece)
|
|
77
|
+
shifts.add(("<<", shift_amount, 0xFFFFFFFF))
|
|
75
78
|
elif piece.op == "And" and isinstance(piece.operands[1], Const):
|
|
76
79
|
and_amount = piece.operands[1].value
|
|
77
80
|
and_core = piece.operands[0]
|
|
78
81
|
if (
|
|
79
82
|
isinstance(and_core, BinaryOp)
|
|
80
|
-
and and_core.op
|
|
83
|
+
and and_core.op in {"Shl", "Mul"}
|
|
81
84
|
and isinstance(and_core.operands[1], Const)
|
|
82
85
|
):
|
|
83
86
|
cores.add(and_core.operands[0])
|
|
84
|
-
|
|
87
|
+
shift_amount = get_expr_shift_left_amount(and_core)
|
|
88
|
+
shifts.add(("<<", shift_amount, and_amount))
|
|
85
89
|
elif (
|
|
86
90
|
isinstance(and_core, BinaryOp)
|
|
87
91
|
and and_core.op == "Shr"
|
|
@@ -112,9 +116,9 @@ class Bswap(PeepholeOptimizationExprBase):
|
|
|
112
116
|
if (
|
|
113
117
|
(
|
|
114
118
|
isinstance(inner_first, BinaryOp)
|
|
115
|
-
and inner_first.op
|
|
119
|
+
and inner_first.op in {"Shl", "Mul"}
|
|
116
120
|
and isinstance(inner_first.operands[1], Const)
|
|
117
|
-
and inner_first
|
|
121
|
+
and get_expr_shift_left_amount(inner_first) == 8
|
|
118
122
|
)
|
|
119
123
|
and (
|
|
120
124
|
isinstance(inner_second, BinaryOp)
|
|
@@ -3,6 +3,7 @@ from math import gcd
|
|
|
3
3
|
|
|
4
4
|
from ailment.expression import BinaryOp, UnaryOp, Const, Convert, StackBaseOffset
|
|
5
5
|
|
|
6
|
+
from angr.utils.bits import sign_extend
|
|
6
7
|
from .base import PeepholeOptimizationExprBase
|
|
7
8
|
|
|
8
9
|
|
|
@@ -59,22 +60,50 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
|
|
|
59
60
|
expr.signed,
|
|
60
61
|
**expr.tags,
|
|
61
62
|
)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
63
|
+
op0, op1 = expr.operands
|
|
64
|
+
if op0.likes(op1):
|
|
65
|
+
# x + x => 2 * x
|
|
66
|
+
count = Const(expr.idx, None, 2, op0.bits, **expr.tags)
|
|
67
|
+
return BinaryOp(expr.idx, "Mul", [op0, count], expr.signed, **expr.tags)
|
|
68
|
+
|
|
69
|
+
op0_is_mulconst = (
|
|
70
|
+
isinstance(op0, BinaryOp)
|
|
71
|
+
and op0.op == "Mul"
|
|
72
|
+
and (isinstance(op0.operands[0], Const) or isinstance(op0.operands[1], Const))
|
|
73
|
+
)
|
|
74
|
+
op1_is_mulconst = (
|
|
75
|
+
isinstance(op1, BinaryOp)
|
|
76
|
+
and op1.op == "Mul"
|
|
77
|
+
and (isinstance(op1.operands[0], Const) or isinstance(op1.operands[1], Const))
|
|
78
|
+
)
|
|
79
|
+
const0, x0 = None, None
|
|
80
|
+
const1, x1 = None, None
|
|
81
|
+
if op0_is_mulconst:
|
|
82
|
+
if isinstance(op0.operands[0], Const):
|
|
83
|
+
const0, x0 = op0.operands
|
|
84
|
+
elif isinstance(op0.operands[1], Const):
|
|
85
|
+
x0, const0 = op0.operands
|
|
86
|
+
if op1_is_mulconst:
|
|
87
|
+
if isinstance(op1.operands[0], Const):
|
|
88
|
+
const1, x1 = op1.operands
|
|
89
|
+
elif isinstance(op1.operands[1], Const):
|
|
90
|
+
x1, const1 = op1.operands
|
|
91
|
+
|
|
92
|
+
if op0_is_mulconst ^ op1_is_mulconst:
|
|
93
|
+
if x0 is not None and const0 is not None and x0.likes(op1):
|
|
94
|
+
# x * A + x => (A + 1) * x
|
|
95
|
+
new_const = Const(const0.idx, None, const0.value + 1, const0.bits, **const0.tags)
|
|
96
|
+
return BinaryOp(expr.idx, "Mul", [x0, new_const], expr.signed, **expr.tags)
|
|
97
|
+
if x1 is not None and const1 is not None and x1.likes(op0):
|
|
98
|
+
# x + x * A => (A + 1) * x
|
|
99
|
+
new_const = Const(const1.idx, None, const1.value + 1, const1.bits, **const1.tags)
|
|
100
|
+
return BinaryOp(expr.idx, "Mul", [x1, new_const], expr.signed, **expr.tags)
|
|
101
|
+
elif op0_is_mulconst and op1_is_mulconst:
|
|
102
|
+
if x0.likes(x1):
|
|
103
|
+
# x * A + x * B => (A + B) * x
|
|
104
|
+
new_const = Const(const0.idx, None, const0.value + const1.value, const0.bits, **const0.tags)
|
|
105
|
+
return BinaryOp(expr.idx, "Mul", [x0, new_const], expr.signed, **expr.tags)
|
|
106
|
+
|
|
78
107
|
elif expr.op == "Sub":
|
|
79
108
|
if isinstance(expr.operands[0], Const) and isinstance(expr.operands[1], Const):
|
|
80
109
|
mask = (1 << expr.bits) - 1
|
|
@@ -119,12 +148,25 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
|
|
|
119
148
|
|
|
120
149
|
elif expr.op == "Mul":
|
|
121
150
|
if isinstance(expr.operands[1], Const) and expr.operands[1].value == 1:
|
|
151
|
+
# x * 1 => x
|
|
122
152
|
return expr.operands[0]
|
|
123
153
|
if isinstance(expr.operands[0], Const) and isinstance(expr.operands[1], Const):
|
|
154
|
+
# constant multiplication
|
|
124
155
|
mask = (1 << expr.bits) - 1
|
|
125
156
|
return Const(
|
|
126
157
|
expr.idx, None, (expr.operands[0].value * expr.operands[1].value) & mask, expr.bits, **expr.tags
|
|
127
158
|
)
|
|
159
|
+
if {type(expr.operands[0]), type(expr.operands[1])} == {BinaryOp, Const}:
|
|
160
|
+
op0, op1 = expr.operands
|
|
161
|
+
const_, x0 = (op0, op1) if isinstance(op0, Const) else (op1, op0)
|
|
162
|
+
if x0.op == "Mul" and (isinstance(x0.operands[0], Const) or isinstance(x0.operands[1], Const)):
|
|
163
|
+
# (A * x) * C => (A * C) * x
|
|
164
|
+
if isinstance(x0.operands[0], Const):
|
|
165
|
+
const_x0, x = x0.operands[0], x0.operands[1]
|
|
166
|
+
else:
|
|
167
|
+
const_x0, x = x0.operands[1], x0.operands[0]
|
|
168
|
+
new_const = Const(const_.idx, None, const_.value * const_x0.value, const_.bits, **const_x0.tags)
|
|
169
|
+
return BinaryOp(expr.idx, "Mul", [x, new_const], expr.signed, bits=expr.bits, **expr.tags)
|
|
128
170
|
|
|
129
171
|
elif (
|
|
130
172
|
expr.op == "Div"
|
|
@@ -197,6 +239,42 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
|
|
|
197
239
|
if expr.operands[0].likes(expr.operands[1]):
|
|
198
240
|
return expr.operands[0]
|
|
199
241
|
|
|
242
|
+
elif expr.op in {"CmpEQ", "CmpLE", "CmpGE"}:
|
|
243
|
+
if expr.operands[0].likes(expr.operands[1]):
|
|
244
|
+
# x == x => 1
|
|
245
|
+
return Const(expr.idx, None, 1, 1, **expr.tags)
|
|
246
|
+
if isinstance(expr.operands[0], Const) and isinstance(expr.operands[1], Const):
|
|
247
|
+
if expr.op == "CmpEQ":
|
|
248
|
+
return Const(
|
|
249
|
+
expr.idx, None, 1 if expr.operands[0].value == expr.operands[1].value else 0, 1, **expr.tags
|
|
250
|
+
)
|
|
251
|
+
if expr.op == "CmpLE":
|
|
252
|
+
return Const(
|
|
253
|
+
expr.idx, None, 1 if expr.operands[0].value <= expr.operands[1].value else 0, 1, **expr.tags
|
|
254
|
+
)
|
|
255
|
+
if expr.op == "CmpGE":
|
|
256
|
+
return Const(
|
|
257
|
+
expr.idx, None, 1 if expr.operands[0].value >= expr.operands[1].value else 0, 1, **expr.tags
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
elif expr.op in {"CmpNE", "CmpLT", "CmpGT"}:
|
|
261
|
+
if expr.operands[0].likes(expr.operands[1]):
|
|
262
|
+
# x != x => 0
|
|
263
|
+
return Const(expr.idx, None, 0, 1, **expr.tags)
|
|
264
|
+
if isinstance(expr.operands[0], Const) and isinstance(expr.operands[1], Const):
|
|
265
|
+
if expr.op == "CmpNE":
|
|
266
|
+
return Const(
|
|
267
|
+
expr.idx, None, 1 if expr.operands[0].value != expr.operands[1].value else 0, 1, **expr.tags
|
|
268
|
+
)
|
|
269
|
+
if expr.op == "CmpLT":
|
|
270
|
+
return Const(
|
|
271
|
+
expr.idx, None, 1 if expr.operands[0].value < expr.operands[1].value else 0, 1, **expr.tags
|
|
272
|
+
)
|
|
273
|
+
if expr.op == "CmpGT":
|
|
274
|
+
return Const(
|
|
275
|
+
expr.idx, None, 1 if expr.operands[0].value > expr.operands[1].value else 0, 1, **expr.tags
|
|
276
|
+
)
|
|
277
|
+
|
|
200
278
|
return None
|
|
201
279
|
|
|
202
280
|
@staticmethod
|
|
@@ -225,8 +303,11 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
|
|
|
225
303
|
and expr.from_type == Convert.TYPE_INT
|
|
226
304
|
and expr.to_type == Convert.TYPE_INT
|
|
227
305
|
and expr.from_bits <= expr.to_bits
|
|
228
|
-
and expr.is_signed is False
|
|
229
306
|
):
|
|
230
|
-
|
|
231
|
-
|
|
307
|
+
if expr.is_signed is False:
|
|
308
|
+
# unsigned extension
|
|
309
|
+
return Const(expr.idx, expr.operand.variable, expr.operand.value, expr.to_bits, **expr.operand.tags)
|
|
310
|
+
# signed extension
|
|
311
|
+
v = sign_extend(expr.operand.value, expr.to_bits)
|
|
312
|
+
return Const(expr.idx, expr.operand.variable, v, expr.to_bits, **expr.operand.tags)
|
|
232
313
|
return None
|
|
@@ -22,9 +22,26 @@ class RemoveNoopConversions(PeepholeOptimizationExprBase):
|
|
|
22
22
|
and expr.to_bits < expr.from_bits
|
|
23
23
|
and expr.from_bits == inner.to_bits
|
|
24
24
|
and expr.is_signed == inner.is_signed
|
|
25
|
+
and expr.from_type == expr.to_type == inner.from_type == inner.to_type == Convert.TYPE_INT
|
|
25
26
|
):
|
|
26
27
|
# extension then truncation (e.g., 1->64->1) can be removed, but truncation then extension cannot be
|
|
27
28
|
# removed (e.g., the high 32 bits must be removed during 64->32->64)
|
|
28
29
|
return inner.operand
|
|
30
|
+
if (
|
|
31
|
+
expr.to_bits < expr.from_bits
|
|
32
|
+
and expr.from_bits == inner.to_bits
|
|
33
|
+
and inner.to_bits <= inner.from_bits
|
|
34
|
+
and expr.is_signed == inner.is_signed
|
|
35
|
+
and expr.from_type == expr.to_type == inner.from_type == inner.to_type == Convert.TYPE_INT
|
|
36
|
+
):
|
|
37
|
+
# merging two truncations into one
|
|
38
|
+
return Convert(
|
|
39
|
+
expr.idx,
|
|
40
|
+
inner.from_bits,
|
|
41
|
+
expr.to_bits,
|
|
42
|
+
expr.is_signed,
|
|
43
|
+
inner.operand,
|
|
44
|
+
**expr.tags,
|
|
45
|
+
)
|
|
29
46
|
|
|
30
47
|
return None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pylint: disable=missing-class-docstring
|
|
1
|
+
# pylint: disable=missing-class-docstring,too-many-boolean-expressions
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
from ailment.expression import BinaryOp, Convert, Const
|
|
4
4
|
|
|
@@ -9,9 +9,18 @@ class RemoveRedundantConversions(PeepholeOptimizationExprBase):
|
|
|
9
9
|
__slots__ = ()
|
|
10
10
|
|
|
11
11
|
NAME = "Remove redundant conversions around binary operators"
|
|
12
|
-
expr_classes = (BinaryOp,)
|
|
12
|
+
expr_classes = (BinaryOp, Convert)
|
|
13
13
|
|
|
14
|
-
def optimize(self, expr: BinaryOp, **kwargs):
|
|
14
|
+
def optimize(self, expr: BinaryOp | Convert, **kwargs):
|
|
15
|
+
|
|
16
|
+
if isinstance(expr, BinaryOp):
|
|
17
|
+
return self._optimize_BinaryOp(expr)
|
|
18
|
+
if isinstance(expr, Convert):
|
|
19
|
+
return self._optimize_Convert(expr)
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
@staticmethod
|
|
23
|
+
def _optimize_BinaryOp(expr: BinaryOp):
|
|
15
24
|
# TODO make this lhs/rhs agnostic
|
|
16
25
|
if isinstance(expr.operands[0], Convert):
|
|
17
26
|
# check: is the lhs convert an up-cast and is rhs a const?
|
|
@@ -156,3 +165,33 @@ class RemoveRedundantConversions(PeepholeOptimizationExprBase):
|
|
|
156
165
|
)
|
|
157
166
|
|
|
158
167
|
return None
|
|
168
|
+
|
|
169
|
+
@staticmethod
|
|
170
|
+
def _optimize_Convert(expr: Convert):
|
|
171
|
+
operand_expr = expr.operand
|
|
172
|
+
if isinstance(operand_expr, BinaryOp) and operand_expr.op in {
|
|
173
|
+
"Mul",
|
|
174
|
+
"Shl",
|
|
175
|
+
"Div",
|
|
176
|
+
"DivMod",
|
|
177
|
+
"Mod",
|
|
178
|
+
"Add",
|
|
179
|
+
"Sub",
|
|
180
|
+
}:
|
|
181
|
+
op0, op1 = operand_expr.operands
|
|
182
|
+
if (
|
|
183
|
+
isinstance(op0, Convert)
|
|
184
|
+
and isinstance(op1, Convert)
|
|
185
|
+
and op0.from_bits == op1.from_bits
|
|
186
|
+
and op0.to_bits == op1.to_bits
|
|
187
|
+
and expr.from_bits == op0.to_bits
|
|
188
|
+
and expr.to_bits == op1.from_bits
|
|
189
|
+
):
|
|
190
|
+
return BinaryOp(
|
|
191
|
+
operand_expr.idx,
|
|
192
|
+
operand_expr.op,
|
|
193
|
+
[op0.operand, op1.operand],
|
|
194
|
+
expr.is_signed,
|
|
195
|
+
**operand_expr.tags,
|
|
196
|
+
)
|
|
197
|
+
return None
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
# pylint:disable=no-self-use,missing-class-docstring
|
|
1
2
|
from __future__ import annotations
|
|
2
3
|
from ailment.expression import BinaryOp, Const, Convert
|
|
3
4
|
|
|
4
5
|
from .base import PeepholeOptimizationExprBase
|
|
6
|
+
from .utils import get_expr_shift_left_amount
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
class RemoveRedundantShifts(PeepholeOptimizationExprBase):
|
|
@@ -15,8 +17,8 @@ class RemoveRedundantShifts(PeepholeOptimizationExprBase):
|
|
|
15
17
|
if expr.op in ("Shr", "Sar") and isinstance(expr.operands[1], Const):
|
|
16
18
|
expr_a = expr.operands[0]
|
|
17
19
|
n0 = expr.operands[1].value
|
|
18
|
-
if isinstance(expr_a, BinaryOp) and expr_a.op
|
|
19
|
-
n1 = expr_a
|
|
20
|
+
if isinstance(expr_a, BinaryOp) and expr_a.op in {"Shl", "Mul"} and isinstance(expr_a.operands[1], Const):
|
|
21
|
+
n1 = get_expr_shift_left_amount(expr_a)
|
|
20
22
|
if n0 == n1:
|
|
21
23
|
inner_expr = expr_a.operands[0]
|
|
22
24
|
conv_inner_expr = Convert(
|
|
@@ -3,6 +3,7 @@ from ailment.statement import Assignment
|
|
|
3
3
|
from ailment.expression import BinaryOp, Const, Tmp
|
|
4
4
|
|
|
5
5
|
from .base import PeepholeOptimizationStmtBase
|
|
6
|
+
from .utils import get_expr_shift_left_amount
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class RolRorRewriter(PeepholeOptimizationStmtBase):
|
|
@@ -61,38 +62,64 @@ class RolRorRewriter(PeepholeOptimizationStmtBase):
|
|
|
61
62
|
if not (isinstance(stmt1_op1, Const) and isinstance(stmt2_op1, Const)):
|
|
62
63
|
return None
|
|
63
64
|
|
|
64
|
-
if
|
|
65
|
+
if (
|
|
66
|
+
stmt_1.src.op in {"Shl", "Mul"}
|
|
67
|
+
and stmt_2.src.op == "Shr"
|
|
68
|
+
and (shiftleft_amount := get_expr_shift_left_amount(stmt_1.src)) is not None
|
|
69
|
+
and shiftleft_amount + stmt2_op1.value == stmt.dst.bits
|
|
70
|
+
):
|
|
71
|
+
rol_amount = Const(None, None, shiftleft_amount, 8, **stmt1_op1.tags)
|
|
65
72
|
return Assignment(
|
|
66
73
|
stmt.idx,
|
|
67
74
|
stmt.dst,
|
|
68
|
-
BinaryOp(None, "Rol", [stmt1_op0,
|
|
75
|
+
BinaryOp(None, "Rol", [stmt1_op0, rol_amount], False, bits=stmt.dst.bits, **stmt_1.src.tags),
|
|
69
76
|
**stmt.tags,
|
|
70
77
|
)
|
|
71
|
-
if
|
|
78
|
+
if (
|
|
79
|
+
stmt_1.src.op == "Shr"
|
|
80
|
+
and stmt_2.src.op in {"Shl", "Mul"}
|
|
81
|
+
and (shiftleft_amount := get_expr_shift_left_amount(stmt_2.src)) is not None
|
|
82
|
+
and stmt1_op1.value + shiftleft_amount == stmt.dst.bits
|
|
83
|
+
):
|
|
72
84
|
return Assignment(
|
|
73
85
|
stmt.idx,
|
|
74
86
|
stmt.dst,
|
|
75
87
|
BinaryOp(None, "Ror", [stmt1_op0, stmt1_op1], False, bits=stmt.dst.bits, **stmt_1.src.tags),
|
|
76
88
|
**stmt.tags,
|
|
77
89
|
)
|
|
78
|
-
elif
|
|
90
|
+
elif (
|
|
91
|
+
isinstance(op0, BinaryOp)
|
|
92
|
+
and isinstance(op1, BinaryOp)
|
|
93
|
+
and {op0.op, op1.op} in [{"Shl", "Shr"}, {"Mul", "Shr"}]
|
|
94
|
+
):
|
|
79
95
|
if not op0.operands[0].likes(op1.operands[0]):
|
|
80
96
|
return None
|
|
81
97
|
|
|
82
98
|
if not isinstance(op0.operands[1], Const) or not isinstance(op1.operands[1], Const):
|
|
83
99
|
return None
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
100
|
+
op0_v = op0.operands[1].value
|
|
101
|
+
op1_v = op1.operands[1].value
|
|
102
|
+
|
|
103
|
+
if (
|
|
104
|
+
op0.op in {"Shl", "Mul"}
|
|
105
|
+
and op1.op == "Shr"
|
|
106
|
+
and (op0_shiftamount := get_expr_shift_left_amount(op0)) is not None
|
|
107
|
+
and op0_shiftamount + op1_v == stmt.dst.bits
|
|
108
|
+
):
|
|
109
|
+
shiftamount = Const(None, None, op0_shiftamount, 8, **op0.operands[1].tags)
|
|
89
110
|
return Assignment(
|
|
90
111
|
stmt.idx,
|
|
91
112
|
stmt.dst,
|
|
92
113
|
BinaryOp(None, "Rol", [op0.operands[0], shiftamount], False, bits=stmt.dst.bits, **op0.tags),
|
|
93
114
|
**stmt.tags,
|
|
94
115
|
)
|
|
95
|
-
if
|
|
116
|
+
if (
|
|
117
|
+
op0.op == "Shr"
|
|
118
|
+
and op1.op in {"Shl", "Mul"}
|
|
119
|
+
and (op1_shiftamount := get_expr_shift_left_amount(op1)) is not None
|
|
120
|
+
and op0_v + op1_shiftamount == stmt.dst.bits
|
|
121
|
+
):
|
|
122
|
+
shiftamount = op0.operands[1]
|
|
96
123
|
return Assignment(
|
|
97
124
|
stmt.idx,
|
|
98
125
|
stmt.dst,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# pylint:disable=missing-class-docstring,no-self-use
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from ailment.expression import BinaryOp, Const
|
|
4
|
+
|
|
5
|
+
from .base import PeepholeOptimizationExprBase
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ShlToMul(PeepholeOptimizationExprBase):
|
|
9
|
+
__slots__ = ()
|
|
10
|
+
|
|
11
|
+
NAME = "a << A => a * (2 ** A)"
|
|
12
|
+
expr_classes = (BinaryOp,) # all expressions are allowed
|
|
13
|
+
|
|
14
|
+
def optimize(self, expr: BinaryOp, **kwargs):
|
|
15
|
+
if expr.op == "Shl" and isinstance(expr.operands[1], Const):
|
|
16
|
+
mul_amount = Const(None, None, 2 ** expr.operands[1].value, expr.operands[0].bits)
|
|
17
|
+
return BinaryOp(
|
|
18
|
+
expr.idx,
|
|
19
|
+
"Mul",
|
|
20
|
+
[expr.operands[0], mul_amount],
|
|
21
|
+
expr.signed,
|
|
22
|
+
**expr.tags,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
return None
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from ailment.expression import BinaryOp, Const
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def get_expr_shift_left_amount(expr: BinaryOp) -> int | None:
|
|
6
|
+
"""
|
|
7
|
+
Get the shift amount of a shift-left or multiplication operation if the shift amount is a constant.
|
|
8
|
+
|
|
9
|
+
:param expr: The shift-left or multiplication expression (must be a BinaryOp).
|
|
10
|
+
:return: The shift amount if it is a constant, or None if it is not.
|
|
11
|
+
"""
|
|
12
|
+
if expr.op == "Shl" and isinstance(expr.operands[1], Const):
|
|
13
|
+
return expr.operands[1].value
|
|
14
|
+
if expr.op == "Mul" and isinstance(expr.operands[1], Const):
|
|
15
|
+
v = expr.operands[1].value
|
|
16
|
+
if v & (v - 1) == 0:
|
|
17
|
+
return v.bit_length() - 1
|
|
18
|
+
return None
|
|
@@ -19,7 +19,6 @@ from angr.analyses.decompiler.optimization_passes import (
|
|
|
19
19
|
FlipBooleanCmp,
|
|
20
20
|
InlinedStringTransformationSimplifier,
|
|
21
21
|
CallStatementRewriter,
|
|
22
|
-
MultiSimplifier,
|
|
23
22
|
DeadblockRemover,
|
|
24
23
|
SwitchReusedEntryRewriter,
|
|
25
24
|
)
|
|
@@ -32,7 +31,6 @@ preset_fast = DecompilationPreset(
|
|
|
32
31
|
StackCanarySimplifier,
|
|
33
32
|
WinStackCanarySimplifier,
|
|
34
33
|
BasePointerSaveSimplifier,
|
|
35
|
-
MultiSimplifier, # TODO: MultiSimplifier should be replaced by a peephole optimization
|
|
36
34
|
ConstantDereferencesSimplifier,
|
|
37
35
|
RetAddrSaveSimplifier,
|
|
38
36
|
X86GccGetPcSimplifier,
|
|
@@ -6,7 +6,6 @@ from angr.analyses.decompiler.optimization_passes import (
|
|
|
6
6
|
WinStackCanarySimplifier,
|
|
7
7
|
BasePointerSaveSimplifier,
|
|
8
8
|
DivSimplifier,
|
|
9
|
-
MultiSimplifier,
|
|
10
9
|
ModSimplifier,
|
|
11
10
|
ConstantDereferencesSimplifier,
|
|
12
11
|
RetAddrSaveSimplifier,
|
|
@@ -38,7 +37,6 @@ preset_full = DecompilationPreset(
|
|
|
38
37
|
WinStackCanarySimplifier,
|
|
39
38
|
BasePointerSaveSimplifier,
|
|
40
39
|
DivSimplifier,
|
|
41
|
-
MultiSimplifier,
|
|
42
40
|
ModSimplifier,
|
|
43
41
|
ConstantDereferencesSimplifier,
|
|
44
42
|
RetAddrSaveSimplifier,
|
|
@@ -56,8 +56,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
|
|
|
56
56
|
self._rewrite_tmps = rewrite_tmps
|
|
57
57
|
self._ail_manager = ail_manager
|
|
58
58
|
self._engine_ail = SimEngineSSARewriting(
|
|
59
|
-
self.project
|
|
60
|
-
project=self.project,
|
|
59
|
+
self.project,
|
|
61
60
|
sp_tracker=sp_tracker,
|
|
62
61
|
bp_as_gpr=bp_as_gpr,
|
|
63
62
|
udef_to_phiid=self._udef_to_phiid,
|