angr 9.2.131__py3-none-macosx_11_0_arm64.whl → 9.2.132__py3-none-macosx_11_0_arm64.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 +108 -34
- 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/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/remove_noop_conversions.py +2 -0
- angr/analyses/decompiler/ssailification/rewriting.py +1 -2
- angr/analyses/decompiler/ssailification/rewriting_engine.py +138 -55
- 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 +5 -3
- angr/analyses/decompiler/structuring/phoenix.py +26 -9
- 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 +18 -3
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +9 -5
- angr/analyses/typehoon/simple_solver.py +7 -5
- angr/analyses/typehoon/translator.py +8 -0
- angr/analyses/typehoon/typeconsts.py +10 -2
- angr/analyses/typehoon/typevars.py +9 -7
- angr/analyses/variable_recovery/engine_ail.py +299 -259
- angr/analyses/variable_recovery/engine_base.py +135 -117
- 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 +1 -1
- 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.dylib +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 +12 -0
- angr/utils/orderedset.py +4 -1
- angr/utils/ssa/__init__.py +21 -3
- {angr-9.2.131.dist-info → angr-9.2.132.dist-info}/METADATA +6 -6
- {angr-9.2.131.dist-info → angr-9.2.132.dist-info}/RECORD +110 -111
- angr/analyses/propagator/engine_ail.py +0 -1562
- angr/storage/memory_mixins/__init__.pyi +0 -48
- {angr-9.2.131.dist-info → angr-9.2.132.dist-info}/LICENSE +0 -0
- {angr-9.2.131.dist-info → angr-9.2.132.dist-info}/WHEEL +0 -0
- {angr-9.2.131.dist-info → angr-9.2.132.dist-info}/entry_points.txt +0 -0
- {angr-9.2.131.dist-info → angr-9.2.132.dist-info}/top_level.txt +0 -0
angr/analyses/ddg.py
CHANGED
|
@@ -2,8 +2,10 @@ from __future__ import annotations
|
|
|
2
2
|
import logging
|
|
3
3
|
from collections import defaultdict
|
|
4
4
|
|
|
5
|
+
import claripy
|
|
5
6
|
import networkx
|
|
6
7
|
import pyvex
|
|
8
|
+
|
|
7
9
|
from . import Analysis
|
|
8
10
|
|
|
9
11
|
from angr.code_location import CodeLocation
|
|
@@ -1030,9 +1032,9 @@ class DDG(Analysis):
|
|
|
1030
1032
|
|
|
1031
1033
|
if not action.data.reg_deps and not action.data.tmp_deps:
|
|
1032
1034
|
# might be a constant assignment
|
|
1033
|
-
v = action.data.ast
|
|
1035
|
+
v: claripy.ast.BV = action.data.ast
|
|
1034
1036
|
if not v.symbolic:
|
|
1035
|
-
const_var = SimConstantVariable(v.concrete_value)
|
|
1037
|
+
const_var = SimConstantVariable(value=v.concrete_value, size=v.size())
|
|
1036
1038
|
const_progvar = ProgramVariable(const_var, prog_var.location)
|
|
1037
1039
|
self._data_graph_add_edge(const_progvar, prog_var, type="mem_data")
|
|
1038
1040
|
|
|
@@ -1109,7 +1111,8 @@ class DDG(Analysis):
|
|
|
1109
1111
|
elif isinstance(statement.data, pyvex.IRExpr.Const):
|
|
1110
1112
|
# assignment
|
|
1111
1113
|
const = statement.data.con.value
|
|
1112
|
-
|
|
1114
|
+
size = statement.data.con.size
|
|
1115
|
+
self._ast_graph.add_edge(ProgramVariable(SimConstantVariable(value=const, size=size), location), pv)
|
|
1113
1116
|
|
|
1114
1117
|
def _handle_reg_read(self, action, location, state, statement): # pylint:disable=unused-argument
|
|
1115
1118
|
reg_offset = action.offset
|
|
@@ -1140,7 +1143,7 @@ class DDG(Analysis):
|
|
|
1140
1143
|
elif reg_offset == self.project.arch.bp_offset:
|
|
1141
1144
|
self._custom_data_per_statement = ("bp", 0)
|
|
1142
1145
|
|
|
1143
|
-
def _handle_reg_write(self, action, location, state, statement): # pylint:disable=unused-argument
|
|
1146
|
+
def _handle_reg_write(self, action, location, state, statement: pyvex.stmt.Put): # pylint:disable=unused-argument
|
|
1144
1147
|
reg_offset = action.offset
|
|
1145
1148
|
variable = SimRegisterVariable(reg_offset, action.data.ast.size() // 8)
|
|
1146
1149
|
|
|
@@ -1157,9 +1160,9 @@ class DDG(Analysis):
|
|
|
1157
1160
|
if not action.reg_deps and not action.tmp_deps:
|
|
1158
1161
|
# moving a constant into the register
|
|
1159
1162
|
# try to parse out the constant from statement
|
|
1160
|
-
const_variable = SimConstantVariable()
|
|
1163
|
+
const_variable = SimConstantVariable(size=1)
|
|
1161
1164
|
if statement is not None and isinstance(statement.data, pyvex.IRExpr.Const):
|
|
1162
|
-
const_variable = SimConstantVariable(value=statement.data.con.value)
|
|
1165
|
+
const_variable = SimConstantVariable(value=statement.data.con.value, size=statement.data.con.size)
|
|
1163
1166
|
const_pv = ProgramVariable(const_variable, location, arch=self.project.arch)
|
|
1164
1167
|
self._data_graph_add_edge(const_pv, pv)
|
|
1165
1168
|
|
|
@@ -1187,7 +1190,7 @@ class DDG(Analysis):
|
|
|
1187
1190
|
ast = None
|
|
1188
1191
|
|
|
1189
1192
|
tmp = action.tmp
|
|
1190
|
-
pv = ProgramVariable(SimTemporaryVariable(tmp), location, arch=self.project.arch)
|
|
1193
|
+
pv = ProgramVariable(SimTemporaryVariable(tmp, len(action.data)), location, arch=self.project.arch)
|
|
1191
1194
|
|
|
1192
1195
|
if ast is not None:
|
|
1193
1196
|
for operand in ast.operands:
|
|
@@ -1230,12 +1233,12 @@ class DDG(Analysis):
|
|
|
1230
1233
|
if not action.tmp_deps and not self._variables_per_statement and not ast:
|
|
1231
1234
|
# read in a constant
|
|
1232
1235
|
# try to parse out the constant from statement
|
|
1233
|
-
const_variable = SimConstantVariable()
|
|
1236
|
+
const_variable = SimConstantVariable(size=1)
|
|
1234
1237
|
if statement is not None:
|
|
1235
1238
|
if isinstance(statement, pyvex.IRStmt.Dirty):
|
|
1236
1239
|
l.warning("Dirty statements are not supported in DDG for now.")
|
|
1237
1240
|
elif isinstance(statement.data, pyvex.IRExpr.Const):
|
|
1238
|
-
const_variable = SimConstantVariable(value=statement.data.con.value)
|
|
1241
|
+
const_variable = SimConstantVariable(value=statement.data.con.value, size=statement.data.con.size)
|
|
1239
1242
|
const_pv = ProgramVariable(const_variable, location, arch=self.project.arch)
|
|
1240
1243
|
self._data_graph_add_edge(const_pv, pv)
|
|
1241
1244
|
|
|
@@ -1296,7 +1299,7 @@ class DDG(Analysis):
|
|
|
1296
1299
|
const_value = expr_1.ast.args[0]
|
|
1297
1300
|
tmp = next(iter(expr_0.tmp_deps))
|
|
1298
1301
|
|
|
1299
|
-
const_def = ProgramVariable(SimConstantVariable(const_value), location)
|
|
1302
|
+
const_def = ProgramVariable(SimConstantVariable(value=const_value, size=len(expr_1.ast)), location)
|
|
1300
1303
|
tmp_def = self._temp_variables[tmp]
|
|
1301
1304
|
return AST("-", tmp_def, const_def)
|
|
1302
1305
|
|
|
@@ -1310,7 +1313,7 @@ class DDG(Analysis):
|
|
|
1310
1313
|
const_value = expr_1.ast.args[0]
|
|
1311
1314
|
tmp = next(iter(expr_0.tmp_deps))
|
|
1312
1315
|
|
|
1313
|
-
const_def = ProgramVariable(SimConstantVariable(const_value), location)
|
|
1316
|
+
const_def = ProgramVariable(SimConstantVariable(value=const_value, size=len(expr_1.ast)), location)
|
|
1314
1317
|
tmp_def = self._temp_variables[tmp]
|
|
1315
1318
|
return AST("+", tmp_def, const_def)
|
|
1316
1319
|
|
|
@@ -24,6 +24,7 @@ from ailment.expression import (
|
|
|
24
24
|
VirtualVariable,
|
|
25
25
|
)
|
|
26
26
|
|
|
27
|
+
from angr.analyses.s_propagator import SPropagatorAnalysis
|
|
27
28
|
from angr.analyses.s_reaching_definitions import SRDAModel
|
|
28
29
|
from angr.utils.ail import is_phi_assignment, HasExprWalker
|
|
29
30
|
from angr.code_location import CodeLocation, ExternalCodeLocation
|
|
@@ -213,11 +214,11 @@ class AILSimplifier(Analysis):
|
|
|
213
214
|
self._reaching_definitions = rd
|
|
214
215
|
return rd
|
|
215
216
|
|
|
216
|
-
def _compute_propagation(self, immediate_stmt_removal: bool = False):
|
|
217
|
+
def _compute_propagation(self, immediate_stmt_removal: bool = False) -> SPropagatorAnalysis:
|
|
217
218
|
# Propagate expressions or return the existing result
|
|
218
219
|
if self._propagator is not None:
|
|
219
220
|
return self._propagator
|
|
220
|
-
prop = self.project.analyses.
|
|
221
|
+
prop = self.project.analyses[SPropagatorAnalysis].prep()(
|
|
221
222
|
subject=self.func,
|
|
222
223
|
func_graph=self.func_graph,
|
|
223
224
|
# gp=self._gp,
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
import logging
|
|
4
4
|
from typing import TYPE_CHECKING
|
|
5
|
-
from collections.abc import Iterable
|
|
5
|
+
from collections.abc import Iterable, Mapping
|
|
6
6
|
|
|
7
7
|
from ailment.statement import Statement, Assignment, Call, Store, Jump
|
|
8
|
-
from ailment.expression import Tmp, Load, Const, Register, Convert
|
|
8
|
+
from ailment.expression import Tmp, Load, Const, Register, Convert, Expression
|
|
9
9
|
from ailment import AILBlockWalkerBase
|
|
10
10
|
|
|
11
11
|
from angr.code_location import ExternalCodeLocation, CodeLocation
|
|
@@ -139,7 +139,7 @@ class BlockSimplifier(Analysis):
|
|
|
139
139
|
|
|
140
140
|
self.result_block = block
|
|
141
141
|
|
|
142
|
-
def _compute_propagation(self, block):
|
|
142
|
+
def _compute_propagation(self, block) -> SPropagatorAnalysis:
|
|
143
143
|
if self._propagator is None:
|
|
144
144
|
self._propagator = self.project.analyses[SPropagatorAnalysis].prep()(
|
|
145
145
|
subject=block,
|
|
@@ -155,7 +155,6 @@ class BlockSimplifier(Analysis):
|
|
|
155
155
|
.prep()(
|
|
156
156
|
subject=block,
|
|
157
157
|
track_tmps=True,
|
|
158
|
-
stack_pointer_tracker=self._stack_pointer_tracker,
|
|
159
158
|
func_addr=self.func_addr,
|
|
160
159
|
)
|
|
161
160
|
.model
|
|
@@ -201,8 +200,8 @@ class BlockSimplifier(Analysis):
|
|
|
201
200
|
|
|
202
201
|
@staticmethod
|
|
203
202
|
def _replace_and_build(
|
|
204
|
-
block,
|
|
205
|
-
replacements,
|
|
203
|
+
block: Block,
|
|
204
|
+
replacements: Mapping[CodeLocation, Mapping[Expression, Expression]],
|
|
206
205
|
replace_assignment_dsts: bool = False,
|
|
207
206
|
replace_loads: bool = False,
|
|
208
207
|
gp: int | None = None,
|
|
@@ -211,14 +210,9 @@ class BlockSimplifier(Analysis):
|
|
|
211
210
|
new_statements = block.statements[::]
|
|
212
211
|
replaced = False
|
|
213
212
|
|
|
214
|
-
stmts_to_remove = set()
|
|
215
213
|
for codeloc, repls in replacements.items():
|
|
216
214
|
for old, new in repls.items():
|
|
217
|
-
|
|
218
|
-
if isinstance(new, dict):
|
|
219
|
-
stmt_to_remove = new["stmt_to_remove"]
|
|
220
|
-
new = new["expr"]
|
|
221
|
-
|
|
215
|
+
assert codeloc.stmt_idx is not None
|
|
222
216
|
stmt = new_statements[codeloc.stmt_idx]
|
|
223
217
|
if (
|
|
224
218
|
not replace_loads
|
|
@@ -229,7 +223,9 @@ class BlockSimplifier(Analysis):
|
|
|
229
223
|
# skip memory-based replacement for non-Call and non-gp-loading statements
|
|
230
224
|
continue
|
|
231
225
|
if stmt == old:
|
|
232
|
-
#
|
|
226
|
+
# the replacement must be a call, since replacements can only be expressions
|
|
227
|
+
# and call is the only thing which is both a statement and an expression
|
|
228
|
+
assert isinstance(new, Call)
|
|
233
229
|
r = True
|
|
234
230
|
new_stmt = new
|
|
235
231
|
else:
|
|
@@ -257,20 +253,13 @@ class BlockSimplifier(Analysis):
|
|
|
257
253
|
r, new_stmt = stmt.replace(old, new)
|
|
258
254
|
|
|
259
255
|
if r:
|
|
256
|
+
assert new_stmt is not None
|
|
260
257
|
replaced = True
|
|
261
258
|
new_statements[codeloc.stmt_idx] = new_stmt
|
|
262
|
-
if stmt_to_remove is not None:
|
|
263
|
-
stmts_to_remove.add(stmt_to_remove)
|
|
264
259
|
|
|
265
260
|
if not replaced:
|
|
266
261
|
return False, block
|
|
267
262
|
|
|
268
|
-
if stmts_to_remove:
|
|
269
|
-
stmt_ids_to_remove = {a.stmt_idx for a in stmts_to_remove}
|
|
270
|
-
all_stmts = {idx: stmt for idx, stmt in enumerate(new_statements) if idx not in stmt_ids_to_remove}
|
|
271
|
-
filtered_stmts = sorted(all_stmts.items(), key=lambda x: x[0])
|
|
272
|
-
new_statements = [stmt for _, stmt in filtered_stmts]
|
|
273
|
-
|
|
274
263
|
new_block = block.copy()
|
|
275
264
|
new_block.statements = new_statements
|
|
276
265
|
return True, new_block
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint:disable=too-many-boolean-expressions
|
|
1
2
|
from __future__ import annotations
|
|
2
3
|
from typing import Any, NamedTuple, TYPE_CHECKING
|
|
3
4
|
import copy
|
|
@@ -12,6 +13,7 @@ import capstone
|
|
|
12
13
|
|
|
13
14
|
import ailment
|
|
14
15
|
|
|
16
|
+
from angr.analyses.decompiler.ssailification.ssailification import Ssailification
|
|
15
17
|
from angr.errors import AngrDecompilationError
|
|
16
18
|
from angr.knowledge_base import KnowledgeBase
|
|
17
19
|
from angr.knowledge_plugins.functions import Function
|
|
@@ -268,6 +270,7 @@ class Clinic(Analysis):
|
|
|
268
270
|
def _decompilation_fixups(self, ail_graph):
|
|
269
271
|
is_pcode_arch = ":" in self.project.arch.name
|
|
270
272
|
|
|
273
|
+
self._remove_redundant_jump_blocks(ail_graph)
|
|
271
274
|
# _fix_abnormal_switch_case_heads may re-lift from VEX blocks, so it should be placed as high up as possible
|
|
272
275
|
self._fix_abnormal_switch_case_heads(ail_graph)
|
|
273
276
|
if self._rewrite_ites_to_diamonds:
|
|
@@ -1359,10 +1362,9 @@ class Clinic(Analysis):
|
|
|
1359
1362
|
|
|
1360
1363
|
@timethis
|
|
1361
1364
|
def _transform_to_ssa_level0(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
|
|
1362
|
-
ssailification = self.project.analyses.
|
|
1365
|
+
ssailification = self.project.analyses[Ssailification].prep(fail_fast=self._fail_fast)(
|
|
1363
1366
|
self.function,
|
|
1364
1367
|
ail_graph,
|
|
1365
|
-
fail_fast=self._fail_fast,
|
|
1366
1368
|
entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
|
|
1367
1369
|
ail_manager=self._ail_manager,
|
|
1368
1370
|
ssa_stackvars=False,
|
|
@@ -1932,10 +1934,12 @@ class Clinic(Analysis):
|
|
|
1932
1934
|
break
|
|
1933
1935
|
|
|
1934
1936
|
def _create_triangle_for_ite_expression(self, ail_graph, block_addr: int, ite_ins_addr: int):
|
|
1935
|
-
|
|
1936
|
-
ite_insn_size =
|
|
1937
|
+
ite_insn_only_block = self.project.factory.block(ite_ins_addr, num_inst=1)
|
|
1938
|
+
ite_insn_size = ite_insn_only_block.size
|
|
1937
1939
|
if ite_insn_size <= 2: # we need an address for true_block and another address for false_block
|
|
1938
1940
|
return None
|
|
1941
|
+
if ite_insn_only_block.vex.exit_statements:
|
|
1942
|
+
return None
|
|
1939
1943
|
|
|
1940
1944
|
# relift the head and the ITE instruction
|
|
1941
1945
|
new_head = self.project.factory.block(
|
|
@@ -2037,6 +2041,10 @@ class Clinic(Analysis):
|
|
|
2037
2041
|
):
|
|
2038
2042
|
return None
|
|
2039
2043
|
|
|
2044
|
+
# corner-case: the last statement of original_block might have been patched by _remove_redundant_jump_blocks.
|
|
2045
|
+
# we detect such case and fix it in new_head_ail
|
|
2046
|
+
self._remove_redundant_jump_blocks_repatch_relifted_block(original_block, end_block_ail)
|
|
2047
|
+
|
|
2040
2048
|
ail_graph.remove_node(original_block)
|
|
2041
2049
|
|
|
2042
2050
|
if end_block_ail not in ail_graph:
|
|
@@ -2142,15 +2150,15 @@ class Clinic(Analysis):
|
|
|
2142
2150
|
),
|
|
2143
2151
|
None,
|
|
2144
2152
|
)
|
|
2153
|
+
intended_head_block = self.project.factory.block(
|
|
2154
|
+
intended_head.addr, size=intended_head.original_size
|
|
2155
|
+
)
|
|
2145
2156
|
if comparison_stmt is not None:
|
|
2146
|
-
intended_head_block = self.project.factory.block(
|
|
2147
|
-
intended_head.addr, size=intended_head.original_size
|
|
2148
|
-
)
|
|
2149
2157
|
cmp_rpos = len(
|
|
2150
2158
|
intended_head_block.instruction_addrs
|
|
2151
2159
|
) - intended_head_block.instruction_addrs.index(comparison_stmt.ins_addr)
|
|
2152
2160
|
else:
|
|
2153
|
-
cmp_rpos = 2
|
|
2161
|
+
cmp_rpos = min(len(intended_head_block.instruction_addrs), 2)
|
|
2154
2162
|
self._fix_abnormal_switch_case_heads_case2(
|
|
2155
2163
|
ail_graph,
|
|
2156
2164
|
candidate,
|
|
@@ -2216,7 +2224,6 @@ class Clinic(Analysis):
|
|
|
2216
2224
|
if isinstance(stmt, ailment.Stmt.Assignment)
|
|
2217
2225
|
and isinstance(stmt.src, ailment.Expr.BinaryOp)
|
|
2218
2226
|
and stmt.src.op in ailment.Expr.BinaryOp.COMPARISON_NEGATION
|
|
2219
|
-
and isinstance(stmt.src.operands[1], ailment.Expr.Const)
|
|
2220
2227
|
and stmt.ins_addr == last_stmt_0.ins_addr
|
|
2221
2228
|
),
|
|
2222
2229
|
None,
|
|
@@ -2228,7 +2235,6 @@ class Clinic(Analysis):
|
|
|
2228
2235
|
if isinstance(stmt, ailment.Stmt.Assignment)
|
|
2229
2236
|
and isinstance(stmt.src, ailment.Expr.BinaryOp)
|
|
2230
2237
|
and stmt.src.op in ailment.Expr.BinaryOp.COMPARISON_NEGATION
|
|
2231
|
-
and isinstance(stmt.src.operands[1], ailment.Expr.Const)
|
|
2232
2238
|
and stmt.ins_addr == last_stmt_1.ins_addr
|
|
2233
2239
|
),
|
|
2234
2240
|
None,
|
|
@@ -2270,51 +2276,86 @@ class Clinic(Analysis):
|
|
|
2270
2276
|
# split the intended head into two
|
|
2271
2277
|
intended_head_block = self.project.factory.block(intended_head.addr, size=intended_head.original_size)
|
|
2272
2278
|
split_ins_addr = intended_head_block.instruction_addrs[-intended_head_split_insns]
|
|
2273
|
-
|
|
2279
|
+
# note that the two blocks can be fully overlapping, so block_0 will be empty...
|
|
2280
|
+
intended_head_block_0 = (
|
|
2281
|
+
self.project.factory.block(intended_head.addr, size=split_ins_addr - intended_head.addr)
|
|
2282
|
+
if split_ins_addr != intended_head.addr
|
|
2283
|
+
else None
|
|
2284
|
+
)
|
|
2274
2285
|
intended_head_block_1 = self.project.factory.block(
|
|
2275
2286
|
split_ins_addr, size=intended_head.addr + intended_head.original_size - split_ins_addr
|
|
2276
2287
|
)
|
|
2277
|
-
intended_head_0 = self._convert_vex(intended_head_block_0)
|
|
2288
|
+
intended_head_0 = self._convert_vex(intended_head_block_0) if intended_head_block_0 is not None else None
|
|
2278
2289
|
intended_head_1 = self._convert_vex(intended_head_block_1)
|
|
2279
2290
|
|
|
2291
|
+
# corner-case: the last statement of intended_head might have been patched by _remove_redundant_jump_blocks. we
|
|
2292
|
+
# detect such case and fix it in intended_head_1
|
|
2293
|
+
self._remove_redundant_jump_blocks_repatch_relifted_block(intended_head, intended_head_1)
|
|
2294
|
+
|
|
2280
2295
|
# adjust the graph accordingly
|
|
2281
2296
|
preds = list(ail_graph.predecessors(intended_head))
|
|
2282
2297
|
succs = list(ail_graph.successors(intended_head))
|
|
2283
2298
|
ail_graph.remove_node(intended_head)
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2299
|
+
|
|
2300
|
+
if intended_head_0 is None:
|
|
2301
|
+
# perfect overlap; the first block is empty
|
|
2302
|
+
for pred in preds:
|
|
2303
|
+
if pred is intended_head:
|
|
2304
|
+
ail_graph.add_edge(intended_head_1, intended_head_1)
|
|
2305
|
+
else:
|
|
2306
|
+
ail_graph.add_edge(pred, intended_head_1)
|
|
2307
|
+
for succ in succs:
|
|
2308
|
+
if succ is intended_head:
|
|
2309
|
+
ail_graph.add_edge(intended_head_1, intended_head_1)
|
|
2310
|
+
else:
|
|
2311
|
+
ail_graph.add_edge(intended_head_1, succ)
|
|
2312
|
+
else:
|
|
2313
|
+
ail_graph.add_edge(intended_head_0, intended_head_1)
|
|
2314
|
+
for pred in preds:
|
|
2315
|
+
if pred is intended_head:
|
|
2316
|
+
ail_graph.add_edge(intended_head_1, intended_head_0)
|
|
2317
|
+
else:
|
|
2318
|
+
ail_graph.add_edge(pred, intended_head_0)
|
|
2319
|
+
for succ in succs:
|
|
2320
|
+
if succ is intended_head:
|
|
2321
|
+
ail_graph.add_edge(intended_head_1, intended_head_0)
|
|
2322
|
+
else:
|
|
2323
|
+
ail_graph.add_edge(intended_head_1, succ)
|
|
2295
2324
|
|
|
2296
2325
|
# split other heads
|
|
2297
2326
|
for o in other_heads:
|
|
2298
2327
|
if other_head_split_insns > 0:
|
|
2299
2328
|
o_block = self.project.factory.block(o.addr, size=o.original_size)
|
|
2300
2329
|
o_split_addr = o_block.instruction_addrs[-other_head_split_insns]
|
|
2301
|
-
new_o_block =
|
|
2302
|
-
|
|
2330
|
+
new_o_block = (
|
|
2331
|
+
self.project.factory.block(o.addr, size=o_split_addr - o.addr) if o_split_addr != o.addr else None
|
|
2332
|
+
)
|
|
2333
|
+
new_head = self._convert_vex(new_o_block) if new_o_block is not None else None
|
|
2303
2334
|
else:
|
|
2304
2335
|
new_head = o
|
|
2305
2336
|
|
|
2306
|
-
if
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
):
|
|
2311
|
-
# update the jump target
|
|
2312
|
-
new_head.statements[-1] = ailment.Stmt.Jump(
|
|
2313
|
-
new_head.statements[-1].idx,
|
|
2337
|
+
if new_head is None:
|
|
2338
|
+
# the head is removed - let's replace it with a jump to the target
|
|
2339
|
+
jump_stmt = ailment.Stmt.Jump(
|
|
2340
|
+
None,
|
|
2314
2341
|
ailment.Expr.Const(None, None, intended_head_1.addr, self.project.arch.bits),
|
|
2315
2342
|
target_idx=intended_head_1.idx,
|
|
2316
|
-
|
|
2343
|
+
ins_addr=o.addr,
|
|
2317
2344
|
)
|
|
2345
|
+
new_head = ailment.Block(o.addr, 1, statements=[jump_stmt], idx=o.idx)
|
|
2346
|
+
else:
|
|
2347
|
+
if (
|
|
2348
|
+
new_head.statements
|
|
2349
|
+
and isinstance(new_head.statements[-1], ailment.Stmt.Jump)
|
|
2350
|
+
and isinstance(new_head.statements[-1].target, ailment.Expr.Const)
|
|
2351
|
+
):
|
|
2352
|
+
# update the jump target
|
|
2353
|
+
new_head.statements[-1] = ailment.Stmt.Jump(
|
|
2354
|
+
new_head.statements[-1].idx,
|
|
2355
|
+
ailment.Expr.Const(None, None, intended_head_1.addr, self.project.arch.bits),
|
|
2356
|
+
target_idx=intended_head_1.idx,
|
|
2357
|
+
**new_head.statements[-1].tags,
|
|
2358
|
+
)
|
|
2318
2359
|
|
|
2319
2360
|
# adjust the graph accordingly
|
|
2320
2361
|
preds = list(ail_graph.predecessors(o))
|
|
@@ -2384,6 +2425,39 @@ class Clinic(Analysis):
|
|
|
2384
2425
|
ail_graph.add_edge(pred, succs[0])
|
|
2385
2426
|
ail_graph.remove_node(node)
|
|
2386
2427
|
|
|
2428
|
+
@staticmethod
|
|
2429
|
+
def _remove_redundant_jump_blocks_repatch_relifted_block(
|
|
2430
|
+
patched_block: ailment.Block, new_block: ailment.Block
|
|
2431
|
+
) -> None:
|
|
2432
|
+
"""
|
|
2433
|
+
The last statement of patched_block might have been patched by _remove_redundant_jump_blocks. In this case, we
|
|
2434
|
+
fix the last instruction for new_block, which is a newly lifted (from VEX) block that ends at the same address
|
|
2435
|
+
as patched_block.
|
|
2436
|
+
|
|
2437
|
+
:param patched_block: Previously patched block.
|
|
2438
|
+
:param new_block: Newly lifted block.
|
|
2439
|
+
"""
|
|
2440
|
+
|
|
2441
|
+
if (
|
|
2442
|
+
isinstance(patched_block.statements[-1], ailment.Stmt.Jump)
|
|
2443
|
+
and isinstance(patched_block.statements[-1].target, ailment.Expr.Const)
|
|
2444
|
+
and isinstance(new_block.statements[-1], ailment.Stmt.Jump)
|
|
2445
|
+
and isinstance(new_block.statements[-1].target, ailment.Expr.Const)
|
|
2446
|
+
and not patched_block.statements[-1].likes(new_block.statements[-1])
|
|
2447
|
+
):
|
|
2448
|
+
new_block.statements[-1].target = patched_block.statements[-1].target
|
|
2449
|
+
if (
|
|
2450
|
+
isinstance(patched_block.statements[-1], ailment.Stmt.ConditionalJump)
|
|
2451
|
+
and isinstance(patched_block.statements[-1].true_target, ailment.Expr.Const)
|
|
2452
|
+
and isinstance(patched_block.statements[-1].false_target, ailment.Expr.Const)
|
|
2453
|
+
and isinstance(new_block.statements[-1], ailment.Stmt.ConditionalJump)
|
|
2454
|
+
and isinstance(new_block.statements[-1].true_target, ailment.Expr.Const)
|
|
2455
|
+
and isinstance(new_block.statements[-1].false_target, ailment.Expr.Const)
|
|
2456
|
+
and not patched_block.statements[-1].likes(new_block.statements[-1])
|
|
2457
|
+
):
|
|
2458
|
+
new_block.statements[-1].true_target = patched_block.statements[-1].true_target
|
|
2459
|
+
new_block.statements[-1].false_target = patched_block.statements[-1].false_target
|
|
2460
|
+
|
|
2387
2461
|
@staticmethod
|
|
2388
2462
|
def _insert_block_labels(ail_graph):
|
|
2389
2463
|
for node in ail_graph.nodes:
|
|
@@ -116,37 +116,37 @@ _ail2claripy_op_mapping = {
|
|
|
116
116
|
"CmpEQ": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) == conv(expr.operands[1], ins_addr=ia),
|
|
117
117
|
"CmpNE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) != conv(expr.operands[1], ins_addr=ia),
|
|
118
118
|
"CmpLE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) <= conv(expr.operands[1], ins_addr=ia),
|
|
119
|
-
"
|
|
119
|
+
"CmpLE (signed)": lambda expr, conv, _, ia: claripy.SLE(
|
|
120
120
|
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
121
121
|
),
|
|
122
122
|
"CmpLT": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) < conv(expr.operands[1], ins_addr=ia),
|
|
123
|
-
"
|
|
123
|
+
"CmpLT (signed)": lambda expr, conv, _, ia: claripy.SLT(
|
|
124
124
|
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
125
125
|
),
|
|
126
126
|
"CmpGE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) >= conv(expr.operands[1], ins_addr=ia),
|
|
127
|
-
"
|
|
127
|
+
"CmpGE (signed)": lambda expr, conv, _, ia: claripy.SGE(
|
|
128
128
|
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
129
129
|
),
|
|
130
130
|
"CmpGT": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) > conv(expr.operands[1], ins_addr=ia),
|
|
131
|
-
"
|
|
131
|
+
"CmpGT (signed)": lambda expr, conv, _, ia: claripy.SGT(
|
|
132
132
|
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
133
133
|
),
|
|
134
134
|
"CasCmpEQ": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) == conv(expr.operands[1], ins_addr=ia),
|
|
135
135
|
"CasCmpNE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) != conv(expr.operands[1], ins_addr=ia),
|
|
136
136
|
"CasCmpLE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) <= conv(expr.operands[1], ins_addr=ia),
|
|
137
|
-
"
|
|
137
|
+
"CasCmpLE (signed)": lambda expr, conv, _, ia: claripy.SLE(
|
|
138
138
|
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
139
139
|
),
|
|
140
140
|
"CasCmpLT": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) < conv(expr.operands[1], ins_addr=ia),
|
|
141
|
-
"
|
|
141
|
+
"CasCmpLT (signed)": lambda expr, conv, _, ia: claripy.SLT(
|
|
142
142
|
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
143
143
|
),
|
|
144
144
|
"CasCmpGE": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) >= conv(expr.operands[1], ins_addr=ia),
|
|
145
|
-
"
|
|
145
|
+
"CasCmpGE (signed)": lambda expr, conv, _, ia: claripy.SGE(
|
|
146
146
|
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
147
147
|
),
|
|
148
148
|
"CasCmpGT": lambda expr, conv, _, ia: conv(expr.operands[0], ins_addr=ia) > conv(expr.operands[1], ins_addr=ia),
|
|
149
|
-
"
|
|
149
|
+
"CasCmpGT (signed)": lambda expr, conv, _, ia: claripy.SGT(
|
|
150
150
|
conv(expr.operands[0], ins_addr=ia), conv(expr.operands[1], ins_addr=ia)
|
|
151
151
|
),
|
|
152
152
|
"Add": lambda expr, conv, _, ia: conv(expr.operands[0], nobool=True, ins_addr=ia)
|
|
@@ -177,10 +177,9 @@ _ail2claripy_op_mapping = {
|
|
|
177
177
|
),
|
|
178
178
|
"Concat": lambda expr, conv, _, ia: claripy.Concat(*[conv(operand, ins_addr=ia) for operand in expr.operands]),
|
|
179
179
|
# There are no corresponding claripy operations for the following operations
|
|
180
|
-
"DivMod": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
181
180
|
"CmpF": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
182
181
|
"Mull": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
183
|
-
"
|
|
182
|
+
"Mull (signed)": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
184
183
|
"Reinterpret": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
185
184
|
"Rol": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
186
185
|
"Ror": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
@@ -190,7 +189,10 @@ _ail2claripy_op_mapping = {
|
|
|
190
189
|
"SBorrow": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
191
190
|
"ExpCmpNE": lambda expr, _, m, *args: _dummy_bools(expr, m),
|
|
192
191
|
"CmpORD": lambda expr, _, m, *args: _dummy_bvs(expr, m), # in case CmpORDRewriter fails
|
|
192
|
+
"CmpEQV": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
193
193
|
"GetMSBs": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
194
|
+
"ShlNV": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
195
|
+
"ShrNV": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
194
196
|
"InterleaveLOV": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
195
197
|
"InterleaveHIV": lambda expr, _, m, *args: _dummy_bvs(expr, m),
|
|
196
198
|
# catch-all
|
|
@@ -37,7 +37,7 @@ class GraphRewritingAnalysis(ForwardAnalysis[None, NodeType, object, object]):
|
|
|
37
37
|
)
|
|
38
38
|
self._graph = ail_graph
|
|
39
39
|
self._vvar_to_vvar = vvar_to_vvar
|
|
40
|
-
self._engine_ail = SimEngineDephiRewriting(self.project
|
|
40
|
+
self._engine_ail = SimEngineDephiRewriting(self.project, self._vvar_to_vvar)
|
|
41
41
|
|
|
42
42
|
self._visited_blocks: set[Any] = set()
|
|
43
43
|
self.out_blocks = {}
|