angr 9.2.130__py3-none-manylinux2014_aarch64.whl → 9.2.132__py3-none-manylinux2014_aarch64.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/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 +124 -123
- 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,50 +1,53 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
from collections import OrderedDict
|
|
3
3
|
|
|
4
|
-
from ailment.statement import
|
|
4
|
+
from ailment.statement import Call, Store, ConditionalJump
|
|
5
5
|
from ailment.expression import Register, BinaryOp, StackBaseOffset, ITE, VEXCCallExpression, Tmp, DirtyExpression
|
|
6
6
|
|
|
7
|
-
from angr.engines.light import
|
|
7
|
+
from angr.engines.light import SimEngineLightAIL
|
|
8
|
+
from angr.project import Project
|
|
8
9
|
from angr.utils.ssa import get_reg_offset_base
|
|
9
10
|
from angr.utils.orderedset import OrderedSet
|
|
10
11
|
from angr.calling_conventions import default_cc
|
|
11
12
|
from .traversal_state import TraversalState
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
class SimEngineSSATraversal(
|
|
15
|
-
SimEngineLightAILMixin,
|
|
16
|
-
SimEngineLight,
|
|
17
|
-
):
|
|
15
|
+
class SimEngineSSATraversal(SimEngineLightAIL[TraversalState, None, None, None]):
|
|
18
16
|
"""
|
|
19
17
|
This engine collects all register and stack variable locations and links them to the block of their creation.
|
|
20
18
|
"""
|
|
21
19
|
|
|
22
|
-
state: TraversalState
|
|
23
|
-
|
|
24
20
|
def __init__(
|
|
25
21
|
self,
|
|
26
|
-
|
|
22
|
+
project: Project,
|
|
27
23
|
simos,
|
|
28
24
|
sp_tracker=None,
|
|
29
25
|
bp_as_gpr: bool = False,
|
|
30
26
|
def_to_loc=None,
|
|
31
27
|
loc_to_defs=None,
|
|
32
28
|
stackvars: bool = False,
|
|
33
|
-
|
|
29
|
+
use_tmps: bool = False,
|
|
34
30
|
):
|
|
35
|
-
super().__init__()
|
|
36
|
-
|
|
37
|
-
self.arch = arch
|
|
31
|
+
super().__init__(project)
|
|
38
32
|
self.simos = simos
|
|
39
33
|
self.sp_tracker = sp_tracker
|
|
40
34
|
self.bp_as_gpr = bp_as_gpr
|
|
41
35
|
self.stackvars = stackvars
|
|
42
|
-
self.
|
|
36
|
+
self.use_tmps = use_tmps
|
|
43
37
|
|
|
44
38
|
self.def_to_loc = def_to_loc if def_to_loc is not None else []
|
|
45
39
|
self.loc_to_defs = loc_to_defs if loc_to_defs is not None else OrderedDict()
|
|
46
40
|
|
|
47
|
-
def
|
|
41
|
+
def _is_top(self, expr):
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
def _top(self, bits):
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
def _process_block_end(self, block, stmt_data, whitelist):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
def _handle_stmt_Assignment(self, stmt):
|
|
48
51
|
if isinstance(stmt.dst, Register):
|
|
49
52
|
codeloc = self._codeloc()
|
|
50
53
|
self.def_to_loc.append((stmt.dst, codeloc))
|
|
@@ -57,7 +60,7 @@ class SimEngineSSATraversal(
|
|
|
57
60
|
|
|
58
61
|
self._expr(stmt.src)
|
|
59
62
|
|
|
60
|
-
def
|
|
63
|
+
def _handle_stmt_Store(self, stmt: Store):
|
|
61
64
|
self._expr(stmt.addr)
|
|
62
65
|
self._expr(stmt.data)
|
|
63
66
|
if stmt.guard is not None:
|
|
@@ -72,14 +75,14 @@ class SimEngineSSATraversal(
|
|
|
72
75
|
|
|
73
76
|
self.state.live_stackvars.add((stmt.addr.offset, stmt.size))
|
|
74
77
|
|
|
75
|
-
def
|
|
78
|
+
def _handle_stmt_ConditionalJump(self, stmt: ConditionalJump):
|
|
76
79
|
self._expr(stmt.condition)
|
|
77
80
|
if stmt.true_target is not None:
|
|
78
81
|
self._expr(stmt.true_target)
|
|
79
82
|
if stmt.false_target is not None:
|
|
80
83
|
self._expr(stmt.false_target)
|
|
81
84
|
|
|
82
|
-
def
|
|
85
|
+
def _handle_stmt_Call(self, stmt: Call):
|
|
83
86
|
|
|
84
87
|
# kill caller-saved registers
|
|
85
88
|
cc = (
|
|
@@ -87,6 +90,7 @@ class SimEngineSSATraversal(
|
|
|
87
90
|
if stmt.calling_convention is None
|
|
88
91
|
else stmt.calling_convention
|
|
89
92
|
)
|
|
93
|
+
assert cc is not None
|
|
90
94
|
for reg_name in cc.CALLER_SAVED_REGS:
|
|
91
95
|
reg_offset = self.arch.registers[reg_name][0]
|
|
92
96
|
base_off = get_reg_offset_base(reg_offset, self.arch)
|
|
@@ -102,11 +106,22 @@ class SimEngineSSATraversal(
|
|
|
102
106
|
base_off = get_reg_offset_base(stmt.ret_expr.reg_offset, self.arch)
|
|
103
107
|
self.state.live_registers.add(base_off)
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
def _handle_stmt_Dummy(self, stmt):
|
|
110
|
+
pass
|
|
111
|
+
|
|
112
|
+
def _handle_stmt_DirtyStatement(self, stmt):
|
|
113
|
+
self._expr(stmt.dirty)
|
|
114
|
+
|
|
115
|
+
def _handle_stmt_Jump(self, stmt):
|
|
116
|
+
self._expr(stmt.target)
|
|
106
117
|
|
|
107
|
-
|
|
118
|
+
_handle_stmt_Label = _handle_stmt_Dummy
|
|
108
119
|
|
|
109
|
-
def
|
|
120
|
+
def _handle_stmt_Return(self, stmt):
|
|
121
|
+
for expr in stmt.ret_exprs:
|
|
122
|
+
self._expr(expr)
|
|
123
|
+
|
|
124
|
+
def _handle_expr_Register(self, expr: Register):
|
|
110
125
|
base_offset = get_reg_offset_base(expr.reg_offset, self.arch)
|
|
111
126
|
|
|
112
127
|
if base_offset not in self.state.live_registers:
|
|
@@ -118,8 +133,8 @@ class SimEngineSSATraversal(
|
|
|
118
133
|
|
|
119
134
|
self.state.live_registers.add(base_offset)
|
|
120
135
|
|
|
121
|
-
def
|
|
122
|
-
if self.
|
|
136
|
+
def _handle_expr_Tmp(self, expr: Tmp):
|
|
137
|
+
if self.use_tmps:
|
|
123
138
|
codeloc = self._codeloc()
|
|
124
139
|
self.def_to_loc.append((expr, codeloc))
|
|
125
140
|
if codeloc not in self.loc_to_defs:
|
|
@@ -128,39 +143,99 @@ class SimEngineSSATraversal(
|
|
|
128
143
|
|
|
129
144
|
self.state.live_tmps.add(expr.tmp_idx)
|
|
130
145
|
|
|
131
|
-
def
|
|
146
|
+
def _handle_binop_Default(self, expr: BinaryOp):
|
|
132
147
|
self._expr(expr.operands[0])
|
|
133
148
|
self._expr(expr.operands[1])
|
|
134
149
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
150
|
+
_handle_binop_CmpLE = _handle_binop_Default
|
|
151
|
+
_handle_binop_CmpLT = _handle_binop_Default
|
|
152
|
+
_handle_binop_CmpGE = _handle_binop_Default
|
|
153
|
+
_handle_binop_CmpGT = _handle_binop_Default
|
|
154
|
+
_handle_binop_CmpEQ = _handle_binop_Default
|
|
155
|
+
_handle_binop_CmpNE = _handle_binop_Default
|
|
156
|
+
_handle_binop_Add = _handle_binop_Default
|
|
157
|
+
_handle_binop_AddF = _handle_binop_Default
|
|
158
|
+
_handle_binop_AddV = _handle_binop_Default
|
|
159
|
+
_handle_binop_And = _handle_binop_Default
|
|
160
|
+
_handle_binop_Carry = _handle_binop_Default
|
|
161
|
+
_handle_binop_CmpF = _handle_binop_Default
|
|
162
|
+
_handle_binop_Concat = _handle_binop_Default
|
|
163
|
+
_handle_binop_Div = _handle_binop_Default
|
|
164
|
+
_handle_binop_DivF = _handle_binop_Default
|
|
165
|
+
_handle_binop_DivV = _handle_binop_Default
|
|
166
|
+
_handle_binop_LogicalAnd = _handle_binop_Default
|
|
167
|
+
_handle_binop_LogicalOr = _handle_binop_Default
|
|
168
|
+
_handle_binop_Mod = _handle_binop_Default
|
|
169
|
+
_handle_binop_Mul = _handle_binop_Default
|
|
170
|
+
_handle_binop_Mull = _handle_binop_Default
|
|
171
|
+
_handle_binop_MulF = _handle_binop_Default
|
|
172
|
+
_handle_binop_MulV = _handle_binop_Default
|
|
173
|
+
_handle_binop_MulHiV = _handle_binop_Default
|
|
174
|
+
_handle_binop_Or = _handle_binop_Default
|
|
175
|
+
_handle_binop_Rol = _handle_binop_Default
|
|
176
|
+
_handle_binop_Ror = _handle_binop_Default
|
|
177
|
+
_handle_binop_SBorrow = _handle_binop_Default
|
|
178
|
+
_handle_binop_SCarry = _handle_binop_Default
|
|
179
|
+
_handle_binop_Sar = _handle_binop_Default
|
|
180
|
+
_handle_binop_Shl = _handle_binop_Default
|
|
181
|
+
_handle_binop_Shr = _handle_binop_Default
|
|
182
|
+
_handle_binop_Sub = _handle_binop_Default
|
|
183
|
+
_handle_binop_SubF = _handle_binop_Default
|
|
184
|
+
_handle_binop_SubV = _handle_binop_Default
|
|
185
|
+
_handle_binop_Xor = _handle_binop_Default
|
|
186
|
+
_handle_binop_InterleaveLOV = _handle_binop_Default
|
|
187
|
+
_handle_binop_InterleaveHIV = _handle_binop_Default
|
|
188
|
+
_handle_binop_CasCmpEQ = _handle_binop_Default
|
|
189
|
+
_handle_binop_CasCmpNE = _handle_binop_Default
|
|
190
|
+
_handle_binop_ExpCmpNE = _handle_binop_Default
|
|
191
|
+
_handle_binop_SarNV = _handle_binop_Default
|
|
192
|
+
_handle_binop_ShrNV = _handle_binop_Default
|
|
193
|
+
_handle_binop_ShlNV = _handle_binop_Default
|
|
194
|
+
_handle_binop_CmpEQV = _handle_binop_Default
|
|
195
|
+
_handle_binop_CmpNEV = _handle_binop_Default
|
|
196
|
+
_handle_binop_CmpGEV = _handle_binop_Default
|
|
197
|
+
_handle_binop_CmpGTV = _handle_binop_Default
|
|
198
|
+
_handle_binop_CmpLEV = _handle_binop_Default
|
|
199
|
+
_handle_binop_CmpLTV = _handle_binop_Default
|
|
200
|
+
_handle_binop_MinV = _handle_binop_Default
|
|
201
|
+
_handle_binop_MaxV = _handle_binop_Default
|
|
202
|
+
_handle_binop_QAddV = _handle_binop_Default
|
|
203
|
+
_handle_binop_QNarrowBinV = _handle_binop_Default
|
|
204
|
+
_handle_binop_PermV = _handle_binop_Default
|
|
205
|
+
_handle_binop_Set = _handle_binop_Default
|
|
206
|
+
|
|
207
|
+
def _handle_unop_Default(self, expr):
|
|
208
|
+
self._expr(expr.operands[0])
|
|
141
209
|
|
|
142
|
-
|
|
210
|
+
_handle_unop_BitwiseNeg = _handle_unop_Default
|
|
211
|
+
_handle_unop_Dereference = _handle_unop_Default
|
|
212
|
+
_handle_unop_Neg = _handle_unop_Default
|
|
213
|
+
_handle_unop_Not = _handle_unop_Default
|
|
214
|
+
_handle_unop_Reference = _handle_unop_Default
|
|
215
|
+
_handle_unop_Clz = _handle_unop_Default
|
|
216
|
+
_handle_unop_Ctz = _handle_unop_Default
|
|
217
|
+
_handle_unop_GetMSBs = _handle_unop_Default
|
|
218
|
+
_handle_unop_unpack = _handle_unop_Default
|
|
219
|
+
_handle_unop_Sqrt = _handle_unop_Default
|
|
220
|
+
_handle_unop_RSqrtEst = _handle_unop_Default
|
|
221
|
+
|
|
222
|
+
def _handle_expr_UnaryOp(self, expr):
|
|
143
223
|
self._expr(expr.operand)
|
|
144
224
|
|
|
145
|
-
def
|
|
146
|
-
self._expr(expr.operands[0])
|
|
147
|
-
self._expr(expr.operands[1])
|
|
148
|
-
|
|
149
|
-
def _handle_TernaryOp(self, expr):
|
|
225
|
+
def _handle_expr_BinaryOp(self, expr):
|
|
150
226
|
self._expr(expr.operands[0])
|
|
151
227
|
self._expr(expr.operands[1])
|
|
152
|
-
self._expr(expr.operands[2])
|
|
153
228
|
|
|
154
|
-
def
|
|
229
|
+
def _handle_expr_ITE(self, expr: ITE):
|
|
155
230
|
self._expr(expr.cond)
|
|
156
231
|
self._expr(expr.iftrue)
|
|
157
232
|
self._expr(expr.iffalse)
|
|
158
233
|
|
|
159
|
-
def
|
|
234
|
+
def _handle_expr_VEXCCallExpression(self, expr: VEXCCallExpression):
|
|
160
235
|
for operand in expr.operands:
|
|
161
236
|
self._expr(operand)
|
|
162
237
|
|
|
163
|
-
def
|
|
238
|
+
def _handle_expr_DirtyExpression(self, expr: DirtyExpression):
|
|
164
239
|
for operand in expr.operands:
|
|
165
240
|
self._expr(operand)
|
|
166
241
|
if expr.guard is not None:
|
|
@@ -171,5 +246,13 @@ class SimEngineSSATraversal(
|
|
|
171
246
|
def _handle_Dummy(self, expr):
|
|
172
247
|
pass
|
|
173
248
|
|
|
174
|
-
|
|
175
|
-
|
|
249
|
+
_handle_expr_VirtualVariable = _handle_Dummy
|
|
250
|
+
_handle_expr_Phi = _handle_Dummy
|
|
251
|
+
_handle_expr_Load = _handle_Dummy
|
|
252
|
+
_handle_expr_Convert = _handle_Dummy
|
|
253
|
+
_handle_expr_Const = _handle_Dummy
|
|
254
|
+
_handle_expr_MultiStatementExpression = _handle_Dummy
|
|
255
|
+
_handle_expr_Reinterpret = _handle_Dummy
|
|
256
|
+
_handle_expr_StackBaseOffset = _handle_Dummy
|
|
257
|
+
_handle_expr_BasePointerOffset = _handle_Dummy
|
|
258
|
+
_handle_expr_Call = _handle_Dummy
|
|
@@ -33,6 +33,7 @@ from angr.sim_type import (
|
|
|
33
33
|
dereference_simtype,
|
|
34
34
|
SimTypeInt128,
|
|
35
35
|
SimTypeInt256,
|
|
36
|
+
SimTypeInt512,
|
|
36
37
|
)
|
|
37
38
|
from angr.knowledge_plugins.functions import Function
|
|
38
39
|
from angr.sim_variable import SimVariable, SimTemporaryVariable, SimStackVariable, SimMemoryVariable
|
|
@@ -52,6 +53,7 @@ from angr.analyses.decompiler.structuring.structurer_nodes import (
|
|
|
52
53
|
LoopNode,
|
|
53
54
|
BreakNode,
|
|
54
55
|
SwitchCaseNode,
|
|
56
|
+
IncompleteSwitchCaseNode,
|
|
55
57
|
ContinueNode,
|
|
56
58
|
CascadingConditionNode,
|
|
57
59
|
)
|
|
@@ -1136,6 +1138,53 @@ class CSwitchCase(CStatement):
|
|
|
1136
1138
|
yield "\n", None
|
|
1137
1139
|
|
|
1138
1140
|
|
|
1141
|
+
class CIncompleteSwitchCase(CStatement):
|
|
1142
|
+
"""
|
|
1143
|
+
Represents an incomplete switch-case construct; this only appear in the decompilation output when switch-case
|
|
1144
|
+
structuring fails (for whatever reason).
|
|
1145
|
+
"""
|
|
1146
|
+
|
|
1147
|
+
__slots__ = ("head", "cases", "tags")
|
|
1148
|
+
|
|
1149
|
+
def __init__(self, head, cases, tags=None, **kwargs):
|
|
1150
|
+
super().__init__(**kwargs)
|
|
1151
|
+
|
|
1152
|
+
self.head = head
|
|
1153
|
+
self.cases: list[tuple[int, CStatements]] = cases
|
|
1154
|
+
self.tags = tags
|
|
1155
|
+
|
|
1156
|
+
def c_repr_chunks(self, indent=0, asexpr=False):
|
|
1157
|
+
indent_str = self.indent_str(indent=indent)
|
|
1158
|
+
paren = CClosingObject("(")
|
|
1159
|
+
brace = CClosingObject("{")
|
|
1160
|
+
|
|
1161
|
+
yield from self.head.c_repr_chunks(indent=indent)
|
|
1162
|
+
yield "\n", None
|
|
1163
|
+
yield indent_str, None
|
|
1164
|
+
yield "switch ", self
|
|
1165
|
+
yield "(", paren
|
|
1166
|
+
yield "/* incomplete */", None
|
|
1167
|
+
yield ")", paren
|
|
1168
|
+
if self.codegen.braces_on_own_lines:
|
|
1169
|
+
yield "\n", None
|
|
1170
|
+
yield indent_str, None
|
|
1171
|
+
else:
|
|
1172
|
+
yield " ", None
|
|
1173
|
+
yield "{", brace
|
|
1174
|
+
yield "\n", None
|
|
1175
|
+
|
|
1176
|
+
# cases
|
|
1177
|
+
for case_addr, case in self.cases:
|
|
1178
|
+
yield indent_str, None
|
|
1179
|
+
yield f"case {case_addr:#x}", self
|
|
1180
|
+
yield ":\n", None
|
|
1181
|
+
yield from case.c_repr_chunks(indent=indent + INDENT_DELTA)
|
|
1182
|
+
|
|
1183
|
+
yield indent_str, None
|
|
1184
|
+
yield "}", brace
|
|
1185
|
+
yield "\n", None
|
|
1186
|
+
|
|
1187
|
+
|
|
1139
1188
|
class CAssignment(CStatement):
|
|
1140
1189
|
"""
|
|
1141
1190
|
a = b
|
|
@@ -1299,6 +1348,8 @@ class CFunctionCall(CStatement, CExpression):
|
|
|
1299
1348
|
if self.show_disambiguated_name and self._is_target_ambiguous(func_name):
|
|
1300
1349
|
func_name = self.callee_func.get_unambiguous_name(display_name=func_name)
|
|
1301
1350
|
yield func_name, self
|
|
1351
|
+
elif isinstance(self.callee_target, str):
|
|
1352
|
+
yield self.callee_target, self
|
|
1302
1353
|
else:
|
|
1303
1354
|
yield from CExpression._try_c_repr_chunks(self.callee_target)
|
|
1304
1355
|
|
|
@@ -1819,7 +1870,6 @@ class CBinaryOp(CExpression):
|
|
|
1819
1870
|
"Mul": self._c_repr_chunks_mul,
|
|
1820
1871
|
"Mull": self._c_repr_chunks_mull,
|
|
1821
1872
|
"Div": self._c_repr_chunks_div,
|
|
1822
|
-
"DivMod": self._c_repr_chunks_divmod,
|
|
1823
1873
|
"Mod": self._c_repr_chunks_mod,
|
|
1824
1874
|
"And": self._c_repr_chunks_and,
|
|
1825
1875
|
"Xor": self._c_repr_chunks_xor,
|
|
@@ -2443,6 +2493,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
2443
2493
|
Block: self._handle_AILBlock,
|
|
2444
2494
|
BreakNode: self._handle_Break,
|
|
2445
2495
|
SwitchCaseNode: self._handle_SwitchCase,
|
|
2496
|
+
IncompleteSwitchCaseNode: self._handle_IncompleteSwitchCase,
|
|
2446
2497
|
ContinueNode: self._handle_Continue,
|
|
2447
2498
|
# AIL statements
|
|
2448
2499
|
Stmt.Store: self._handle_Stmt_Store,
|
|
@@ -2671,16 +2722,16 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
2671
2722
|
# Util methods
|
|
2672
2723
|
#
|
|
2673
2724
|
|
|
2674
|
-
def
|
|
2725
|
+
def default_simtype_from_bits(self, n: int, signed: bool = True) -> SimType:
|
|
2675
2726
|
_mapping = {
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2727
|
+
64: SimTypeLongLong,
|
|
2728
|
+
32: SimTypeInt,
|
|
2729
|
+
16: SimTypeShort,
|
|
2730
|
+
8: SimTypeChar,
|
|
2680
2731
|
}
|
|
2681
2732
|
if n in _mapping:
|
|
2682
2733
|
return _mapping.get(n)(signed=signed).with_arch(self.project.arch)
|
|
2683
|
-
return SimTypeNum(n
|
|
2734
|
+
return SimTypeNum(n, signed=signed).with_arch(self.project.arch)
|
|
2684
2735
|
|
|
2685
2736
|
def _variable(self, variable: SimVariable, fallback_type_size: int | None) -> CVariable:
|
|
2686
2737
|
# TODO: we need to fucking make sure that variable recovery and type inference actually generates a size
|
|
@@ -2690,7 +2741,9 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
2690
2741
|
variable, is_global=isinstance(variable, SimMemoryVariable) and not isinstance(variable, SimStackVariable)
|
|
2691
2742
|
)
|
|
2692
2743
|
if variable_type is None:
|
|
2693
|
-
variable_type = self.
|
|
2744
|
+
variable_type = self.default_simtype_from_bits(
|
|
2745
|
+
(fallback_type_size or self.project.arch.bytes) * self.project.arch.byte_width
|
|
2746
|
+
)
|
|
2694
2747
|
cvar = CVariable(variable, unified_variable=unified, variable_type=variable_type, codegen=self)
|
|
2695
2748
|
self._variables_in_use[variable] = cvar
|
|
2696
2749
|
return cvar
|
|
@@ -3172,6 +3225,12 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3172
3225
|
tags = {"ins_addr": node.addr}
|
|
3173
3226
|
return CSwitchCase(switch_expr, cases, default=default, tags=tags, codegen=self)
|
|
3174
3227
|
|
|
3228
|
+
def _handle_IncompleteSwitchCase(self, node: IncompleteSwitchCaseNode, **kwargs):
|
|
3229
|
+
head = self._handle(node.head, is_expr=False)
|
|
3230
|
+
cases = [(case.addr, self._handle(case, is_expr=False)) for case in node.cases]
|
|
3231
|
+
tags = {"ins_addr": node.addr}
|
|
3232
|
+
return CIncompleteSwitchCase(head, cases, tags=tags, codegen=self)
|
|
3233
|
+
|
|
3175
3234
|
def _handle_Continue(self, node, **kwargs):
|
|
3176
3235
|
tags = {"ins_addr": node.addr}
|
|
3177
3236
|
|
|
@@ -3313,7 +3372,9 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3313
3372
|
if result.is_expr and result.type.size != stmt.size * self.project.arch.byte_width:
|
|
3314
3373
|
result = CTypeCast(
|
|
3315
3374
|
result.type,
|
|
3316
|
-
self.
|
|
3375
|
+
self.default_simtype_from_bits(
|
|
3376
|
+
stmt.size * self.project.arch.byte_width, signed=getattr(result.type, "signed", False)
|
|
3377
|
+
),
|
|
3317
3378
|
result,
|
|
3318
3379
|
codegen=self,
|
|
3319
3380
|
)
|
|
@@ -3376,12 +3437,12 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3376
3437
|
return cvar
|
|
3377
3438
|
offset = 0 if expr.variable_offset is None else expr.variable_offset
|
|
3378
3439
|
# FIXME: The type should be associated to the register expression itself
|
|
3379
|
-
type_ = self.
|
|
3440
|
+
type_ = self.default_simtype_from_bits(expr.bits, signed=False)
|
|
3380
3441
|
return self._access_constant_offset(self._get_variable_reference(cvar), offset, type_, lvalue, negotiate)
|
|
3381
3442
|
return CRegister(expr, tags=expr.tags, codegen=self)
|
|
3382
3443
|
|
|
3383
3444
|
def _handle_Expr_Load(self, expr: Expr.Load, **kwargs):
|
|
3384
|
-
ty = self.
|
|
3445
|
+
ty = self.default_simtype_from_bits(expr.bits)
|
|
3385
3446
|
|
|
3386
3447
|
def negotiate(old_ty: SimType, proposed_ty: SimType) -> SimType:
|
|
3387
3448
|
# we do not allow returning a struct for a primitive type
|
|
@@ -3404,9 +3465,9 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3404
3465
|
|
|
3405
3466
|
def _handle_Expr_Tmp(self, expr: Tmp, **kwargs):
|
|
3406
3467
|
l.warning("FIXME: Leftover Tmp expressions are found.")
|
|
3407
|
-
return self._variable(SimTemporaryVariable(expr.tmp_idx), expr.size)
|
|
3468
|
+
return self._variable(SimTemporaryVariable(expr.tmp_idx, expr.bits), expr.size)
|
|
3408
3469
|
|
|
3409
|
-
def _handle_Expr_Const(self, expr, type_=None, reference_values=None, variable=None, **kwargs):
|
|
3470
|
+
def _handle_Expr_Const(self, expr: Expr.Const, type_=None, reference_values=None, variable=None, **kwargs):
|
|
3410
3471
|
inline_string = False
|
|
3411
3472
|
function_pointer = False
|
|
3412
3473
|
|
|
@@ -3483,7 +3544,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3483
3544
|
|
|
3484
3545
|
if type_ is None:
|
|
3485
3546
|
# default to int
|
|
3486
|
-
type_ = self.
|
|
3547
|
+
type_ = self.default_simtype_from_bits(expr.bits)
|
|
3487
3548
|
|
|
3488
3549
|
if variable is None and hasattr(expr, "reference_variable") and expr.reference_variable is not None:
|
|
3489
3550
|
variable = expr.reference_variable
|
|
@@ -3529,7 +3590,9 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3529
3590
|
def _handle_Expr_Convert(self, expr: Expr.Convert, **kwargs):
|
|
3530
3591
|
# width of converted type is easy
|
|
3531
3592
|
dst_type: SimTypeInt | SimTypeChar
|
|
3532
|
-
if
|
|
3593
|
+
if 512 >= expr.to_bits > 256:
|
|
3594
|
+
dst_type = SimTypeInt512()
|
|
3595
|
+
elif 256 >= expr.to_bits > 128:
|
|
3533
3596
|
dst_type = SimTypeInt256()
|
|
3534
3597
|
elif 128 >= expr.to_bits > 64:
|
|
3535
3598
|
dst_type = SimTypeInt128()
|
|
@@ -3561,7 +3624,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3561
3624
|
# do we need an intermediate cast?
|
|
3562
3625
|
if orig_child_signed != expr.is_signed and expr.to_bits > expr.from_bits:
|
|
3563
3626
|
# this is a problem. sign-extension only happens when the SOURCE of the cast is signed
|
|
3564
|
-
child_ty = self.
|
|
3627
|
+
child_ty = self.default_simtype_from_bits(child.type.size, expr.is_signed)
|
|
3565
3628
|
child = CTypeCast(None, child_ty, child, codegen=self)
|
|
3566
3629
|
|
|
3567
3630
|
return CTypeCast(None, dst_type.with_arch(self.project.arch), child, tags=expr.tags, codegen=self)
|
|
@@ -1192,8 +1192,10 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1192
1192
|
# update node_a
|
|
1193
1193
|
node_a = next(iter(nn for nn in graph.nodes if nn.addr == target))
|
|
1194
1194
|
if isinstance(node_a, IncompleteSwitchCaseNode):
|
|
1195
|
-
self._unpack_incompleteswitchcasenode(graph, node_a)
|
|
1196
|
-
|
|
1195
|
+
r = self._unpack_incompleteswitchcasenode(graph, node_a)
|
|
1196
|
+
if not r:
|
|
1197
|
+
return False
|
|
1198
|
+
self._unpack_incompleteswitchcasenode(full_graph, node_a) # this shall not fail
|
|
1197
1199
|
# update node_a
|
|
1198
1200
|
node_a = next(iter(nn for nn in graph.nodes if nn.addr == target))
|
|
1199
1201
|
|
|
@@ -1308,7 +1310,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1308
1310
|
):
|
|
1309
1311
|
out_nodes = set()
|
|
1310
1312
|
for succ in successors:
|
|
1311
|
-
out_nodes |=
|
|
1313
|
+
out_nodes |= {
|
|
1314
|
+
succ for succ in full_graph.successors(succ) if succ is not node and succ not in successors
|
|
1315
|
+
}
|
|
1312
1316
|
out_nodes = list(out_nodes)
|
|
1313
1317
|
if len(out_nodes) <= 1:
|
|
1314
1318
|
new_node = IncompleteSwitchCaseNode(node.addr, node, successors)
|
|
@@ -1508,7 +1512,10 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1508
1512
|
if node_default is not None:
|
|
1509
1513
|
all_case_nodes.append(node_default)
|
|
1510
1514
|
case_node: SequenceNode = next(nn for nn in all_case_nodes if nn.addr == out_src.addr)
|
|
1511
|
-
|
|
1515
|
+
try:
|
|
1516
|
+
case_node_last_stmt = self.cond_proc.get_last_statement(case_node)
|
|
1517
|
+
except EmptyBlockNotice:
|
|
1518
|
+
case_node_last_stmt = None
|
|
1512
1519
|
if not isinstance(case_node_last_stmt, Jump):
|
|
1513
1520
|
jump_stmt = Jump(
|
|
1514
1521
|
None, Const(None, None, head.addr, self.project.arch.bits), None, ins_addr=out_src.addr
|
|
@@ -1562,6 +1569,15 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1562
1569
|
|
|
1563
1570
|
return case_and_entry_addrs
|
|
1564
1571
|
|
|
1572
|
+
def _is_switch_cases_address_loaded_from_memory_head_or_jumpnode(self, graph, node) -> bool:
|
|
1573
|
+
jump_tables = self.kb.cfgs["CFGFast"].jump_tables
|
|
1574
|
+
if node.addr in jump_tables:
|
|
1575
|
+
return True
|
|
1576
|
+
for succ in graph.successors(node):
|
|
1577
|
+
if succ.addr in jump_tables:
|
|
1578
|
+
return True
|
|
1579
|
+
return node in self.switch_case_known_heads
|
|
1580
|
+
|
|
1565
1581
|
# other acyclic schemas
|
|
1566
1582
|
|
|
1567
1583
|
def _match_acyclic_sequence(self, graph, full_graph, start_node) -> bool:
|
|
@@ -1571,14 +1587,12 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1571
1587
|
succs = list(graph.successors(start_node))
|
|
1572
1588
|
if len(succs) == 1:
|
|
1573
1589
|
end_node = succs[0]
|
|
1574
|
-
jump_tables = self.kb.cfgs["CFGFast"].jump_tables
|
|
1575
1590
|
if (
|
|
1576
1591
|
full_graph.out_degree[start_node] == 1
|
|
1577
1592
|
and full_graph.in_degree[end_node] == 1
|
|
1578
1593
|
and not full_graph.has_edge(end_node, start_node)
|
|
1579
|
-
and
|
|
1580
|
-
and
|
|
1581
|
-
and start_node not in self.switch_case_known_heads
|
|
1594
|
+
and not self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(full_graph, end_node)
|
|
1595
|
+
and not self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(full_graph, start_node)
|
|
1582
1596
|
and end_node not in self.dowhile_known_tail_nodes
|
|
1583
1597
|
):
|
|
1584
1598
|
# merge two blocks
|
|
@@ -1599,7 +1613,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1599
1613
|
succs = list(full_graph.successors(start_node))
|
|
1600
1614
|
if len(succs) == 2:
|
|
1601
1615
|
left, right = succs
|
|
1602
|
-
if
|
|
1616
|
+
if self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(
|
|
1617
|
+
full_graph, left
|
|
1618
|
+
) or self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(full_graph, right):
|
|
1603
1619
|
# structure the switch-case first before we wrap them into an ITE. give up
|
|
1604
1620
|
return False
|
|
1605
1621
|
|
|
@@ -2032,7 +2048,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2032
2048
|
left, right = right, left
|
|
2033
2049
|
|
|
2034
2050
|
# ensure left and right nodes are not the head of a switch-case construct
|
|
2035
|
-
if
|
|
2051
|
+
if self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(
|
|
2052
|
+
full_graph, left
|
|
2053
|
+
) or self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(full_graph, right):
|
|
2036
2054
|
return None
|
|
2037
2055
|
|
|
2038
2056
|
if (
|
|
@@ -2079,7 +2097,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2079
2097
|
left, right = right, left
|
|
2080
2098
|
|
|
2081
2099
|
# ensure left and right nodes are not the head of a switch-case construct
|
|
2082
|
-
if
|
|
2100
|
+
if self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(
|
|
2101
|
+
full_graph, left
|
|
2102
|
+
) or self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(full_graph, right):
|
|
2083
2103
|
return None
|
|
2084
2104
|
|
|
2085
2105
|
if (
|
|
@@ -2120,7 +2140,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2120
2140
|
left, successor = successor, left
|
|
2121
2141
|
|
|
2122
2142
|
# ensure left and successor nodes are not the head of a switch-case construct
|
|
2123
|
-
if
|
|
2143
|
+
if self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(
|
|
2144
|
+
full_graph, left
|
|
2145
|
+
) or self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(full_graph, successor):
|
|
2124
2146
|
return None
|
|
2125
2147
|
|
|
2126
2148
|
if (
|
|
@@ -2168,7 +2190,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2168
2190
|
left, else_node = else_node, left
|
|
2169
2191
|
|
|
2170
2192
|
# ensure left and else nodes are not the head of a switch-case construct
|
|
2171
|
-
if
|
|
2193
|
+
if self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(
|
|
2194
|
+
full_graph, left
|
|
2195
|
+
) or self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(full_graph, else_node):
|
|
2172
2196
|
return None
|
|
2173
2197
|
|
|
2174
2198
|
if (
|
|
@@ -2460,7 +2484,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2460
2484
|
return True, new_seq
|
|
2461
2485
|
|
|
2462
2486
|
@staticmethod
|
|
2463
|
-
def _unpack_incompleteswitchcasenode(graph: networkx.DiGraph, incscnode: IncompleteSwitchCaseNode):
|
|
2487
|
+
def _unpack_incompleteswitchcasenode(graph: networkx.DiGraph, incscnode: IncompleteSwitchCaseNode) -> bool:
|
|
2464
2488
|
preds = list(graph.predecessors(incscnode))
|
|
2465
2489
|
succs = list(graph.successors(incscnode))
|
|
2466
2490
|
if len(succs) <= 1:
|
|
@@ -2471,6 +2495,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2471
2495
|
graph.add_edge(incscnode.head, case_node)
|
|
2472
2496
|
if succs:
|
|
2473
2497
|
graph.add_edge(case_node, succs[0])
|
|
2498
|
+
return True
|
|
2499
|
+
return False
|
|
2474
2500
|
|
|
2475
2501
|
@staticmethod
|
|
2476
2502
|
def _count_statements(node: BaseNode | Block) -> int:
|
|
@@ -411,3 +411,12 @@ class IncompleteSwitchCaseHeadStatement(ailment.statement.Statement):
|
|
|
411
411
|
return ailment.utils.stable_hash(
|
|
412
412
|
(IncompleteSwitchCaseHeadStatement, self.idx, self.switch_variable, self._case_addrs_str)
|
|
413
413
|
)
|
|
414
|
+
|
|
415
|
+
def replace(self, old_expr, new_expr):
|
|
416
|
+
return self
|
|
417
|
+
|
|
418
|
+
def likes(self, other):
|
|
419
|
+
return self == other
|
|
420
|
+
|
|
421
|
+
def matches(self, other):
|
|
422
|
+
return self == other
|