angr 9.2.123__py3-none-manylinux2014_aarch64.whl → 9.2.124__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/cfg/indirect_jump_resolvers/mips_elf_fast.py +11 -8
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_got.py +2 -2
- angr/analyses/decompiler/ail_simplifier.py +16 -19
- angr/analyses/decompiler/callsite_maker.py +8 -7
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +24 -2
- angr/analyses/decompiler/clinic.py +27 -1
- angr/analyses/decompiler/condition_processor.py +10 -3
- angr/analyses/decompiler/decompilation_cache.py +2 -0
- angr/analyses/decompiler/decompiler.py +50 -8
- angr/analyses/decompiler/dephication/graph_vvar_mapping.py +10 -2
- angr/analyses/decompiler/dephication/rewriting_engine.py +64 -1
- angr/analyses/decompiler/expression_narrower.py +5 -1
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +4 -1
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +7 -0
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +23 -4
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +3 -1
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +8 -5
- angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +10 -5
- angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +18 -7
- angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +6 -0
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +2 -0
- angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +2 -0
- angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +8 -2
- angr/analyses/decompiler/region_identifier.py +36 -0
- angr/analyses/decompiler/region_simplifiers/loop.py +2 -8
- angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +9 -3
- angr/analyses/decompiler/ssailification/rewriting.py +5 -2
- angr/analyses/decompiler/ssailification/rewriting_engine.py +151 -25
- angr/analyses/decompiler/ssailification/rewriting_state.py +1 -0
- angr/analyses/decompiler/ssailification/ssailification.py +17 -9
- angr/analyses/decompiler/ssailification/traversal.py +3 -1
- angr/analyses/decompiler/ssailification/traversal_engine.py +35 -8
- angr/analyses/decompiler/ssailification/traversal_state.py +1 -0
- angr/analyses/decompiler/structured_codegen/c.py +42 -4
- angr/analyses/decompiler/structuring/phoenix.py +3 -0
- angr/analyses/propagator/engine_ail.py +10 -3
- angr/analyses/reaching_definitions/engine_ail.py +10 -15
- angr/analyses/s_propagator.py +16 -9
- angr/analyses/s_reaching_definitions/s_rda_view.py +127 -63
- angr/analyses/variable_recovery/engine_ail.py +14 -0
- angr/analyses/variable_recovery/engine_base.py +11 -0
- angr/engines/light/engine.py +12 -0
- angr/knowledge_plugins/__init__.py +2 -0
- angr/knowledge_plugins/decompilation.py +45 -0
- angr/knowledge_plugins/key_definitions/atoms.py +8 -0
- angr/procedures/definitions/parse_win32json.py +2 -1
- angr/storage/memory_mixins/actions_mixin.py +7 -7
- angr/storage/memory_mixins/address_concretization_mixin.py +5 -5
- angr/storage/memory_mixins/bvv_conversion_mixin.py +1 -1
- angr/storage/memory_mixins/clouseau_mixin.py +3 -3
- angr/storage/memory_mixins/conditional_store_mixin.py +3 -3
- angr/storage/memory_mixins/default_filler_mixin.py +3 -3
- angr/storage/memory_mixins/memory_mixin.py +45 -34
- angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +15 -14
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +27 -16
- angr/storage/memory_mixins/paged_memory/pages/cooperation.py +18 -9
- angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +5 -5
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +89 -55
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +16 -25
- angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +11 -9
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +23 -7
- angr/storage/memory_mixins/paged_memory/privileged_mixin.py +1 -1
- angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +9 -7
- angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +9 -9
- angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +1 -0
- angr/storage/memory_mixins/simple_interface_mixin.py +2 -2
- angr/storage/memory_mixins/simplification_mixin.py +2 -2
- angr/storage/memory_mixins/size_resolution_mixin.py +1 -1
- angr/storage/memory_mixins/slotted_memory.py +3 -3
- angr/storage/memory_mixins/smart_find_mixin.py +1 -0
- angr/storage/memory_mixins/underconstrained_mixin.py +5 -5
- angr/storage/memory_mixins/unwrapper_mixin.py +4 -4
- angr/storage/memory_object.py +4 -3
- angr/utils/constants.py +1 -1
- angr/utils/graph.py +15 -0
- angr/vaults.py +2 -2
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/METADATA +6 -6
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/RECORD +83 -82
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/WHEEL +1 -1
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/LICENSE +0 -0
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/entry_points.txt +0 -0
- {angr-9.2.123.dist-info → angr-9.2.124.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
|
@@ -153,6 +153,11 @@ class MipsElfFastResolver(IndirectJumpResolver):
|
|
|
153
153
|
|
|
154
154
|
def _resolve_case_1(self, addr: int, block: pyvex.IRSB, func_addr: int, gp_value: int, cfg) -> int | None:
|
|
155
155
|
# lift the block again with the correct setting
|
|
156
|
+
|
|
157
|
+
inital_regs = [(self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr)]
|
|
158
|
+
if gp_value is not None:
|
|
159
|
+
inital_regs.append((self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value))
|
|
160
|
+
|
|
156
161
|
first_irsb = self.project.factory.block(
|
|
157
162
|
addr,
|
|
158
163
|
size=block.size,
|
|
@@ -160,10 +165,7 @@ class MipsElfFastResolver(IndirectJumpResolver):
|
|
|
160
165
|
const_prop=True,
|
|
161
166
|
cross_insn_opt=False,
|
|
162
167
|
load_from_ro_regions=True,
|
|
163
|
-
initial_regs=
|
|
164
|
-
(self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr),
|
|
165
|
-
(self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value),
|
|
166
|
-
],
|
|
168
|
+
initial_regs=inital_regs,
|
|
167
169
|
).vex_nostmt
|
|
168
170
|
|
|
169
171
|
if not isinstance(first_irsb.next, pyvex.IRExpr.RdTmp):
|
|
@@ -193,6 +195,10 @@ class MipsElfFastResolver(IndirectJumpResolver):
|
|
|
193
195
|
# the register (t9) is set in this block - we can resolve the jump target using only the current block
|
|
194
196
|
return Case2Result.RESUME, None
|
|
195
197
|
|
|
198
|
+
inital_regs = [(self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr)]
|
|
199
|
+
if gp_value is not None:
|
|
200
|
+
inital_regs.append((self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value))
|
|
201
|
+
|
|
196
202
|
# lift the first block again with the correct setting
|
|
197
203
|
first_irsb = self.project.factory.block(
|
|
198
204
|
first_block_addr,
|
|
@@ -200,10 +206,7 @@ class MipsElfFastResolver(IndirectJumpResolver):
|
|
|
200
206
|
collect_data_refs=False,
|
|
201
207
|
const_prop=True,
|
|
202
208
|
load_from_ro_regions=True,
|
|
203
|
-
initial_regs=
|
|
204
|
-
(self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr),
|
|
205
|
-
(self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value),
|
|
206
|
-
],
|
|
209
|
+
initial_regs=inital_regs,
|
|
207
210
|
).vex_nostmt
|
|
208
211
|
|
|
209
212
|
last_reg_setting_tmp = self._get_last_reg_setting_tmp(first_irsb, jump_target_reg)
|
|
@@ -51,11 +51,11 @@ class MipsElfGotResolver(IndirectJumpResolver):
|
|
|
51
51
|
return False, []
|
|
52
52
|
dynsym_addr = self._find_and_cache_section_addr(obj, ".dynsym")
|
|
53
53
|
if dynsym_addr is None:
|
|
54
|
-
return
|
|
54
|
+
return False, []
|
|
55
55
|
|
|
56
56
|
dynstr_addr = self._find_and_cache_section_addr(obj, ".dynstr")
|
|
57
57
|
if dynstr_addr is None:
|
|
58
|
-
return
|
|
58
|
+
return False, []
|
|
59
59
|
|
|
60
60
|
if block.size != 16:
|
|
61
61
|
return False, []
|
|
@@ -1316,18 +1316,7 @@ class AILSimplifier(Analysis):
|
|
|
1316
1316
|
continue
|
|
1317
1317
|
uses = rd.get_vvar_uses(def_.atom)
|
|
1318
1318
|
|
|
1319
|
-
elif def_.atom.was_reg:
|
|
1320
|
-
uses = rd.get_vvar_uses(def_.atom)
|
|
1321
|
-
if (
|
|
1322
|
-
def_.atom.reg_offset in self.project.arch.artificial_registers_offsets
|
|
1323
|
-
and len(uses) == 1
|
|
1324
|
-
and next(iter(uses)) == def_.codeloc
|
|
1325
|
-
):
|
|
1326
|
-
# TODO: Verify if we still need this hack after moving to SSA
|
|
1327
|
-
# cc_ndep = amd64g_calculate_condition(..., cc_ndep)
|
|
1328
|
-
uses = set()
|
|
1329
|
-
|
|
1330
|
-
elif def_.atom.was_parameter:
|
|
1319
|
+
elif def_.atom.was_reg or def_.atom.was_parameter:
|
|
1331
1320
|
uses = rd.get_vvar_uses(def_.atom)
|
|
1332
1321
|
|
|
1333
1322
|
else:
|
|
@@ -1425,9 +1414,17 @@ class AILSimplifier(Analysis):
|
|
|
1425
1414
|
simplified = True
|
|
1426
1415
|
continue
|
|
1427
1416
|
if isinstance(stmt, Assignment) and isinstance(stmt.dst, VirtualVariable):
|
|
1428
|
-
# no one is using the returned virtual variable.
|
|
1429
|
-
# a
|
|
1430
|
-
|
|
1417
|
+
# no one is using the returned virtual variable.
|
|
1418
|
+
# now the things are a bit tricky here
|
|
1419
|
+
if isinstance(stmt.src, Call):
|
|
1420
|
+
# replace this assignment statement with a call statement
|
|
1421
|
+
stmt = stmt.src
|
|
1422
|
+
elif isinstance(stmt.src, Convert) and isinstance(stmt.src.operand, Call):
|
|
1423
|
+
# the convert is useless now
|
|
1424
|
+
stmt = stmt.src.operand
|
|
1425
|
+
else:
|
|
1426
|
+
# we can't change this stmt at all because it has an expression with Calls inside
|
|
1427
|
+
pass
|
|
1431
1428
|
else:
|
|
1432
1429
|
# no calls. remove it
|
|
1433
1430
|
simplified = True
|
|
@@ -1460,7 +1457,7 @@ class AILSimplifier(Analysis):
|
|
|
1460
1457
|
def _find_cyclic_dependent_phis_and_dirty_vvars(self, rd: SRDAModel) -> set[int]:
|
|
1461
1458
|
blocks_dict = {(bb.addr, bb.idx): bb for bb in self.func_graph}
|
|
1462
1459
|
|
|
1463
|
-
# find dirty vvars
|
|
1460
|
+
# find dirty vvars and vexccall vvars
|
|
1464
1461
|
dirty_vvar_ids = set()
|
|
1465
1462
|
for bb in self.func_graph:
|
|
1466
1463
|
for stmt in bb.statements:
|
|
@@ -1468,7 +1465,7 @@ class AILSimplifier(Analysis):
|
|
|
1468
1465
|
isinstance(stmt, Assignment)
|
|
1469
1466
|
and isinstance(stmt.dst, VirtualVariable)
|
|
1470
1467
|
and stmt.dst.was_reg
|
|
1471
|
-
and isinstance(stmt.src, DirtyExpression)
|
|
1468
|
+
and isinstance(stmt.src, (DirtyExpression, VEXCCallExpression))
|
|
1472
1469
|
):
|
|
1473
1470
|
dirty_vvar_ids.add(stmt.dst.varid)
|
|
1474
1471
|
|
|
@@ -1544,8 +1541,8 @@ class AILSimplifier(Analysis):
|
|
|
1544
1541
|
v = False
|
|
1545
1542
|
|
|
1546
1543
|
def _handle_expr(expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement, block) -> Expression | None:
|
|
1547
|
-
if isinstance(expr,
|
|
1548
|
-
rewriter = rewriter_cls(expr
|
|
1544
|
+
if isinstance(expr, VEXCCallExpression):
|
|
1545
|
+
rewriter = rewriter_cls(expr, self.project.arch)
|
|
1549
1546
|
if rewriter.result is not None:
|
|
1550
1547
|
_any_update.v = True
|
|
1551
1548
|
return rewriter.result
|
|
@@ -143,7 +143,7 @@ class CallSiteMaker(Analysis):
|
|
|
143
143
|
if isinstance(arg_loc, SimRegArg):
|
|
144
144
|
size = arg_loc.size
|
|
145
145
|
offset = arg_loc.check_offset(cc.arch)
|
|
146
|
-
value_and_def = self._resolve_register_argument(
|
|
146
|
+
value_and_def = self._resolve_register_argument(arg_loc)
|
|
147
147
|
if value_and_def is not None:
|
|
148
148
|
vvar_def = value_and_def[1]
|
|
149
149
|
arg_vvars.append(vvar_def)
|
|
@@ -283,14 +283,15 @@ class CallSiteMaker(Analysis):
|
|
|
283
283
|
l.warning("TODO: Unsupported statement type %s for definitions.", type(stmt))
|
|
284
284
|
return None
|
|
285
285
|
|
|
286
|
-
def _resolve_register_argument(self,
|
|
286
|
+
def _resolve_register_argument(self, arg_loc) -> tuple[int | None, Expr.VirtualVariable] | None:
|
|
287
287
|
offset = arg_loc.check_offset(self.project.arch)
|
|
288
288
|
|
|
289
289
|
if self._reaching_definitions is not None:
|
|
290
290
|
# Find its definition
|
|
291
|
-
ins_addr = call_stmt.tags["ins_addr"]
|
|
292
291
|
view = SRDAView(self._reaching_definitions.model)
|
|
293
|
-
vvar = view.
|
|
292
|
+
vvar = view.get_reg_vvar_by_stmt(
|
|
293
|
+
offset, self.block.addr, self.block.idx, len(self.block.statements) - 1, OP_BEFORE
|
|
294
|
+
)
|
|
294
295
|
|
|
295
296
|
if vvar is not None:
|
|
296
297
|
vvar_value = view.get_vvar_value(vvar)
|
|
@@ -318,8 +319,8 @@ class CallSiteMaker(Analysis):
|
|
|
318
319
|
if self._reaching_definitions is not None:
|
|
319
320
|
# find its definition
|
|
320
321
|
view = SRDAView(self._reaching_definitions.model)
|
|
321
|
-
vvar = view.
|
|
322
|
-
sp_offset, size,
|
|
322
|
+
vvar = view.get_stack_vvar_by_stmt(
|
|
323
|
+
sp_offset, size, self.block.addr, self.block.idx, len(self.block.statements) - 1, OP_BEFORE
|
|
323
324
|
)
|
|
324
325
|
if vvar is not None:
|
|
325
326
|
value = view.get_vvar_value(vvar)
|
|
@@ -416,7 +417,7 @@ class CallSiteMaker(Analysis):
|
|
|
416
417
|
|
|
417
418
|
value = None
|
|
418
419
|
if isinstance(arg_loc, SimRegArg):
|
|
419
|
-
value_and_def = self._resolve_register_argument(
|
|
420
|
+
value_and_def = self._resolve_register_argument(arg_loc)
|
|
420
421
|
if value_and_def is not None:
|
|
421
422
|
value = value_and_def[0]
|
|
422
423
|
|
|
@@ -20,7 +20,7 @@ class AMD64CCallRewriter(CCallRewriterBase):
|
|
|
20
20
|
__slots__ = ()
|
|
21
21
|
|
|
22
22
|
def _rewrite(self, ccall: Expr.VEXCCallExpression) -> Expr.Expression | None:
|
|
23
|
-
if ccall.
|
|
23
|
+
if ccall.callee == "amd64g_calculate_condition":
|
|
24
24
|
cond = ccall.operands[0]
|
|
25
25
|
op = ccall.operands[1]
|
|
26
26
|
dep_1 = ccall.operands[2]
|
|
@@ -288,6 +288,28 @@ class AMD64CCallRewriter(CCallRewriterBase):
|
|
|
288
288
|
|
|
289
289
|
r = Expr.BinaryOp(ccall.idx, "CmpLT", (dep_1, dep_2), True, **ccall.tags)
|
|
290
290
|
return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
|
|
291
|
+
|
|
292
|
+
if op_v in {
|
|
293
|
+
AMD64_OpTypes["G_CC_OP_LOGICB"],
|
|
294
|
+
AMD64_OpTypes["G_CC_OP_LOGICW"],
|
|
295
|
+
AMD64_OpTypes["G_CC_OP_LOGICL"],
|
|
296
|
+
AMD64_OpTypes["G_CC_OP_LOGICQ"],
|
|
297
|
+
}:
|
|
298
|
+
# dep_1 is the result, dep_2 is always zero
|
|
299
|
+
# dep_1 <s 0
|
|
300
|
+
|
|
301
|
+
dep_1 = self._fix_size(
|
|
302
|
+
dep_1,
|
|
303
|
+
op_v,
|
|
304
|
+
AMD64_OpTypes["G_CC_OP_LOGICB"],
|
|
305
|
+
AMD64_OpTypes["G_CC_OP_LOGICW"],
|
|
306
|
+
AMD64_OpTypes["G_CC_OP_LOGICL"],
|
|
307
|
+
ccall.tags,
|
|
308
|
+
)
|
|
309
|
+
zero = Expr.Const(None, None, 0, dep_1.bits)
|
|
310
|
+
r = Expr.BinaryOp(ccall.idx, "CmpLT", (dep_1, zero), True, **ccall.tags)
|
|
311
|
+
return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
|
|
312
|
+
|
|
291
313
|
elif cond_v == AMD64_CondTypes["CondNBE"]:
|
|
292
314
|
if op_v in {
|
|
293
315
|
AMD64_OpTypes["G_CC_OP_SUBB"],
|
|
@@ -390,7 +412,7 @@ class AMD64CCallRewriter(CCallRewriterBase):
|
|
|
390
412
|
)
|
|
391
413
|
return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
|
|
392
414
|
|
|
393
|
-
elif ccall.
|
|
415
|
+
elif ccall.callee == "amd64g_calculate_rflags_c":
|
|
394
416
|
# calculate the carry flag
|
|
395
417
|
op = ccall.operands[0]
|
|
396
418
|
dep_1 = ccall.operands[1]
|
|
@@ -110,6 +110,7 @@ class Clinic(Analysis):
|
|
|
110
110
|
inlined_counts: dict[int, int] | None = None,
|
|
111
111
|
inlining_parents: set[int] | None = None,
|
|
112
112
|
vvar_id_start: int = 0,
|
|
113
|
+
optimization_scratch: dict[str, Any] | None = None,
|
|
113
114
|
):
|
|
114
115
|
if not func.normalized and mode == ClinicMode.DECOMPILE:
|
|
115
116
|
raise ValueError("Decompilation must work on normalized function graphs.")
|
|
@@ -124,6 +125,7 @@ class Clinic(Analysis):
|
|
|
124
125
|
self.variable_kb = variable_kb
|
|
125
126
|
self.externs: set[SimMemoryVariable] = set()
|
|
126
127
|
self.data_refs: dict[int, int] = {} # data address to instruction address
|
|
128
|
+
self.optimization_scratch = optimization_scratch if optimization_scratch is not None else {}
|
|
127
129
|
|
|
128
130
|
self._func_graph: networkx.DiGraph | None = None
|
|
129
131
|
self._ail_manager = None
|
|
@@ -919,10 +921,16 @@ class Clinic(Analysis):
|
|
|
919
921
|
"Ijk_Sys"
|
|
920
922
|
):
|
|
921
923
|
# we don't support lifting this block. use a dummy block instead
|
|
924
|
+
dirty_expr = ailment.Expr.DirtyExpression(
|
|
925
|
+
self._ail_manager.next_atom,
|
|
926
|
+
f"Unsupported jumpkind {block.vex.jumpkind} at address {block_node.addr}",
|
|
927
|
+
[],
|
|
928
|
+
bits=0,
|
|
929
|
+
)
|
|
922
930
|
statements = [
|
|
923
931
|
ailment.Stmt.DirtyStatement(
|
|
924
932
|
self._ail_manager.next_atom(),
|
|
925
|
-
|
|
933
|
+
dirty_expr,
|
|
926
934
|
ins_addr=block_node.addr,
|
|
927
935
|
)
|
|
928
936
|
]
|
|
@@ -1219,6 +1227,7 @@ class Clinic(Analysis):
|
|
|
1219
1227
|
variable_kb=variable_kb,
|
|
1220
1228
|
vvar_id_start=self.vvar_id_start,
|
|
1221
1229
|
entry_node_addr=self.entry_node_addr,
|
|
1230
|
+
scratch=self.optimization_scratch,
|
|
1222
1231
|
**kwargs,
|
|
1223
1232
|
)
|
|
1224
1233
|
if a.out_graph:
|
|
@@ -1256,6 +1265,7 @@ class Clinic(Analysis):
|
|
|
1256
1265
|
ailment.Expr.VirtualVariableCategory.PARAMETER,
|
|
1257
1266
|
oident=arg.reg,
|
|
1258
1267
|
ins_addr=self.function.addr,
|
|
1268
|
+
vex_block_addr=self.function.addr,
|
|
1259
1269
|
)
|
|
1260
1270
|
self.vvar_id_start += 1
|
|
1261
1271
|
arg_vvars[arg_vvar.varid] = arg_vvar, arg
|
|
@@ -1269,6 +1279,7 @@ class Clinic(Analysis):
|
|
|
1269
1279
|
False,
|
|
1270
1280
|
arg_vvar,
|
|
1271
1281
|
ins_addr=self.function.addr,
|
|
1282
|
+
vex_block_addr=self.function.addr,
|
|
1272
1283
|
)
|
|
1273
1284
|
|
|
1274
1285
|
fullreg_dst = ailment.Expr.Register(
|
|
@@ -1277,12 +1288,14 @@ class Clinic(Analysis):
|
|
|
1277
1288
|
basereg_offset,
|
|
1278
1289
|
basereg_size * self.project.arch.byte_width,
|
|
1279
1290
|
ins_addr=self.function.addr,
|
|
1291
|
+
vex_block_addr=self.function.addr,
|
|
1280
1292
|
)
|
|
1281
1293
|
stmt = ailment.Stmt.Assignment(
|
|
1282
1294
|
self._ail_manager.next_atom(),
|
|
1283
1295
|
fullreg_dst,
|
|
1284
1296
|
arg_vvar,
|
|
1285
1297
|
ins_addr=self.function.addr,
|
|
1298
|
+
vex_block_addr=self.function.addr,
|
|
1286
1299
|
)
|
|
1287
1300
|
new_stmts.append(stmt)
|
|
1288
1301
|
|
|
@@ -1313,6 +1326,7 @@ class Clinic(Analysis):
|
|
|
1313
1326
|
ail_graph,
|
|
1314
1327
|
entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
|
|
1315
1328
|
ail_manager=self._ail_manager,
|
|
1329
|
+
ssa_tmps=True,
|
|
1316
1330
|
ssa_stackvars=True,
|
|
1317
1331
|
vvar_id_start=self.vvar_id_start,
|
|
1318
1332
|
)
|
|
@@ -1792,6 +1806,18 @@ class Clinic(Analysis):
|
|
|
1792
1806
|
elif isinstance(expr, ailment.Stmt.Call):
|
|
1793
1807
|
self._link_variables_on_call(variable_manager, global_variables, block, stmt_idx, expr, is_expr=True)
|
|
1794
1808
|
|
|
1809
|
+
elif isinstance(expr, ailment.Expr.VEXCCallExpression):
|
|
1810
|
+
for operand in expr.operands:
|
|
1811
|
+
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, operand)
|
|
1812
|
+
|
|
1813
|
+
elif isinstance(expr, ailment.Expr.DirtyExpression):
|
|
1814
|
+
for operand in expr.operands:
|
|
1815
|
+
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, operand)
|
|
1816
|
+
if expr.maddr:
|
|
1817
|
+
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.maddr)
|
|
1818
|
+
if expr.guard:
|
|
1819
|
+
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.guard)
|
|
1820
|
+
|
|
1795
1821
|
def _function_graph_to_ail_graph(self, func_graph, blocks_by_addr_and_size=None):
|
|
1796
1822
|
if blocks_by_addr_and_size is None:
|
|
1797
1823
|
blocks_by_addr_and_size = self._blocks_by_addr_and_size
|
|
@@ -160,6 +160,8 @@ _ail2claripy_op_mapping = {
|
|
|
160
160
|
"GetMSBs": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
161
161
|
"InterleaveLOV": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
162
162
|
"InterleaveHIV": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
163
|
+
# catch-all
|
|
164
|
+
"_DUMMY_": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
#
|
|
@@ -771,7 +773,7 @@ class ConditionProcessor:
|
|
|
771
773
|
|
|
772
774
|
if isinstance(
|
|
773
775
|
condition,
|
|
774
|
-
(ailment.Expr.
|
|
776
|
+
(ailment.Expr.VEXCCallExpression, ailment.Expr.BasePointerOffset, ailment.Expr.ITE),
|
|
775
777
|
):
|
|
776
778
|
return _dummy_bvs(condition, self._condition_mapping)
|
|
777
779
|
if isinstance(condition, ailment.Stmt.Call):
|
|
@@ -828,9 +830,14 @@ class ConditionProcessor:
|
|
|
828
830
|
# fall back to op
|
|
829
831
|
lambda_expr = _ail2claripy_op_mapping.get(condition.op, None)
|
|
830
832
|
if lambda_expr is None:
|
|
831
|
-
|
|
832
|
-
|
|
833
|
+
# fall back to the catch-all option
|
|
834
|
+
l.debug(
|
|
835
|
+
"Unsupported AIL expression operation %s (or verbose: %s). Fall back to the default catch-all dummy "
|
|
836
|
+
"option. Consider implementing.",
|
|
837
|
+
condition.op,
|
|
838
|
+
condition.verbose_op,
|
|
833
839
|
)
|
|
840
|
+
lambda_expr = _ail2claripy_op_mapping["_DUMMY_"]
|
|
834
841
|
r = lambda_expr(condition, self.claripy_ast_from_ail_condition, self._condition_mapping)
|
|
835
842
|
|
|
836
843
|
if isinstance(r, claripy.ast.Bool) and nobool:
|
|
@@ -14,6 +14,7 @@ class DecompilationCache:
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
__slots__ = (
|
|
17
|
+
"parameters",
|
|
17
18
|
"addr",
|
|
18
19
|
"type_constraints",
|
|
19
20
|
"func_typevar",
|
|
@@ -25,6 +26,7 @@ class DecompilationCache:
|
|
|
25
26
|
)
|
|
26
27
|
|
|
27
28
|
def __init__(self, addr):
|
|
29
|
+
self.parameters: dict[str, Any] = {}
|
|
28
30
|
self.addr = addr
|
|
29
31
|
self.type_constraints: set | None = None
|
|
30
32
|
self.func_typevar = None
|
|
@@ -68,12 +68,13 @@ class Decompiler(Analysis):
|
|
|
68
68
|
inline_functions=frozenset(),
|
|
69
69
|
update_memory_data: bool = True,
|
|
70
70
|
generate_code: bool = True,
|
|
71
|
+
use_cache: bool = True,
|
|
71
72
|
):
|
|
72
73
|
if not isinstance(func, Function):
|
|
73
74
|
func = self.kb.functions[func]
|
|
74
75
|
self.func: Function = func
|
|
75
76
|
self._cfg = cfg.model if isinstance(cfg, CFGFast) else cfg
|
|
76
|
-
self._options = options
|
|
77
|
+
self._options = options or []
|
|
77
78
|
|
|
78
79
|
if preset is None and optimization_passes:
|
|
79
80
|
self._optimization_passes = optimization_passes
|
|
@@ -102,6 +103,25 @@ class Decompiler(Analysis):
|
|
|
102
103
|
self._update_memory_data = update_memory_data
|
|
103
104
|
self._generate_code = generate_code
|
|
104
105
|
self._inline_functions = inline_functions
|
|
106
|
+
self._cache_parameters = (
|
|
107
|
+
{
|
|
108
|
+
"cfg": self._cfg,
|
|
109
|
+
"variable_kb": self._variable_kb,
|
|
110
|
+
"options": {(o, v) for o, v in self._options if o.category != "Display" and v != o.default_value},
|
|
111
|
+
"optimization_passes": self._optimization_passes,
|
|
112
|
+
"sp_tracker_track_memory": self._sp_tracker_track_memory,
|
|
113
|
+
"peephole_optimizations": self._peephole_optimizations,
|
|
114
|
+
"vars_must_struct": self._vars_must_struct,
|
|
115
|
+
"flavor": self._flavor,
|
|
116
|
+
"expr_comments": self._expr_comments,
|
|
117
|
+
"stmt_comments": self._stmt_comments,
|
|
118
|
+
"ite_exprs": self._ite_exprs,
|
|
119
|
+
"binop_operators": self._binop_operators,
|
|
120
|
+
"inline_functions": self._inline_functions,
|
|
121
|
+
}
|
|
122
|
+
if use_cache
|
|
123
|
+
else None
|
|
124
|
+
)
|
|
105
125
|
|
|
106
126
|
self.clinic = None # mostly for debugging purposes
|
|
107
127
|
self.codegen: CStructuredCodeGenerator | None = None
|
|
@@ -111,27 +131,43 @@ class Decompiler(Analysis):
|
|
|
111
131
|
self.unoptimized_ail_graph: networkx.DiGraph | None = None
|
|
112
132
|
self.ail_graph: networkx.DiGraph | None = None
|
|
113
133
|
self.vvar_id_start = None
|
|
134
|
+
self._optimization_scratch: dict[str, Any] = {}
|
|
114
135
|
|
|
115
136
|
if decompile:
|
|
116
137
|
self._decompile()
|
|
117
138
|
|
|
139
|
+
def _can_use_decompilation_cache(self, cache: DecompilationCache) -> bool:
|
|
140
|
+
a, b = self._cache_parameters, cache.parameters
|
|
141
|
+
id_checks = {"cfg", "variable_kb"}
|
|
142
|
+
return all(a[k] is b[k] if k in id_checks else a[k] == b[k] for k in self._cache_parameters)
|
|
143
|
+
|
|
118
144
|
@timethis
|
|
119
145
|
def _decompile(self):
|
|
120
146
|
if self.func.is_simprocedure:
|
|
121
147
|
return
|
|
122
148
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
149
|
+
cache = None
|
|
150
|
+
|
|
151
|
+
if self._cache_parameters is not None:
|
|
152
|
+
try:
|
|
153
|
+
cache = self.kb.decompilations[self.func.addr]
|
|
154
|
+
if not self._can_use_decompilation_cache(cache):
|
|
155
|
+
cache = None
|
|
156
|
+
except KeyError:
|
|
157
|
+
pass
|
|
158
|
+
|
|
159
|
+
if cache:
|
|
126
160
|
old_codegen = cache.codegen
|
|
127
161
|
old_clinic = cache.clinic
|
|
128
162
|
ite_exprs = cache.ite_exprs if self._ite_exprs is None else self._ite_exprs
|
|
129
163
|
binop_operators = cache.binop_operators if self._binop_operators is None else self._binop_operators
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
binop_operators = self._binop_operators
|
|
164
|
+
l.debug("Decompilation cache hit")
|
|
165
|
+
else:
|
|
133
166
|
old_codegen = None
|
|
134
167
|
old_clinic = None
|
|
168
|
+
ite_exprs = self._ite_exprs
|
|
169
|
+
binop_operators = self._binop_operators
|
|
170
|
+
l.debug("Decompilation cache miss")
|
|
135
171
|
|
|
136
172
|
self.options_by_class = defaultdict(list)
|
|
137
173
|
|
|
@@ -167,6 +203,7 @@ class Decompiler(Analysis):
|
|
|
167
203
|
fold_callexprs_into_conditions = True
|
|
168
204
|
|
|
169
205
|
cache = DecompilationCache(self.func.addr)
|
|
206
|
+
cache.parameters = self._cache_parameters
|
|
170
207
|
cache.ite_exprs = ite_exprs
|
|
171
208
|
cache.binop_operators = binop_operators
|
|
172
209
|
|
|
@@ -189,6 +226,7 @@ class Decompiler(Analysis):
|
|
|
189
226
|
cache=cache,
|
|
190
227
|
progress_callback=progress_callback,
|
|
191
228
|
inline_functions=self._inline_functions,
|
|
229
|
+
optimization_scratch=self._optimization_scratch,
|
|
192
230
|
**self.options_to_params(self.options_by_class["clinic"]),
|
|
193
231
|
)
|
|
194
232
|
else:
|
|
@@ -302,6 +340,8 @@ class Decompiler(Analysis):
|
|
|
302
340
|
self.cache.codegen = codegen
|
|
303
341
|
self.cache.clinic = self.clinic
|
|
304
342
|
|
|
343
|
+
self.kb.decompilations[self.func.addr] = self.cache
|
|
344
|
+
|
|
305
345
|
def _recover_regions(self, graph: networkx.DiGraph, condition_processor, update_graph: bool = True):
|
|
306
346
|
return self.project.analyses[RegionIdentifier].prep(kb=self.kb)(
|
|
307
347
|
self.func,
|
|
@@ -355,6 +395,7 @@ class Decompiler(Analysis):
|
|
|
355
395
|
variable_kb=self._variable_kb,
|
|
356
396
|
reaching_definitions=reaching_definitions,
|
|
357
397
|
entry_node_addr=self.clinic.entry_node_addr,
|
|
398
|
+
scratch=self._optimization_scratch,
|
|
358
399
|
**kwargs,
|
|
359
400
|
)
|
|
360
401
|
|
|
@@ -414,6 +455,7 @@ class Decompiler(Analysis):
|
|
|
414
455
|
reaching_definitions=reaching_definitions,
|
|
415
456
|
vvar_id_start=self.vvar_id_start,
|
|
416
457
|
entry_node_addr=self.clinic.entry_node_addr,
|
|
458
|
+
scratch=self._optimization_scratch,
|
|
417
459
|
**kwargs,
|
|
418
460
|
)
|
|
419
461
|
|
|
@@ -442,7 +484,7 @@ class Decompiler(Analysis):
|
|
|
442
484
|
continue
|
|
443
485
|
|
|
444
486
|
pass_ = timethis(pass_)
|
|
445
|
-
a = pass_(self.func, seq=seq_node, **kwargs)
|
|
487
|
+
a = pass_(self.func, seq=seq_node, scratch=self._optimization_scratch, **kwargs)
|
|
446
488
|
if a.out_seq:
|
|
447
489
|
seq_node = a.out_seq
|
|
448
490
|
|
|
@@ -3,7 +3,7 @@ import logging
|
|
|
3
3
|
from collections import defaultdict
|
|
4
4
|
|
|
5
5
|
from ailment.block import Block
|
|
6
|
-
from ailment.expression import Phi, VirtualVariable
|
|
6
|
+
from ailment.expression import Phi, VirtualVariable, VirtualVariableCategory
|
|
7
7
|
from ailment.statement import Assignment, Jump, ConditionalJump, Label
|
|
8
8
|
|
|
9
9
|
from angr.analyses import Analysis
|
|
@@ -213,8 +213,16 @@ class GraphDephicationVVarMapping(Analysis): # pylint:disable=abstract-method
|
|
|
213
213
|
|
|
214
214
|
the_block = self._blocks[(src_block_addr, src_block_idx)]
|
|
215
215
|
ins_addr = the_block.addr + the_block.original_size - 1
|
|
216
|
+
if vvar.category == VirtualVariableCategory.PARAMETER:
|
|
217
|
+
# it's a parameter, so we copy the variable into a dummy register vvar
|
|
218
|
+
# a parameter vvar should never be assigned to
|
|
219
|
+
new_category = VirtualVariableCategory.REGISTER
|
|
220
|
+
new_oident = 4096
|
|
221
|
+
else:
|
|
222
|
+
new_category = vvar.category
|
|
223
|
+
new_oident = vvar.oident
|
|
216
224
|
new_vvar = VirtualVariable(
|
|
217
|
-
None, new_vvar_id, vvar.bits,
|
|
225
|
+
None, new_vvar_id, vvar.bits, new_category, oident=new_oident, ins_addr=ins_addr
|
|
218
226
|
)
|
|
219
227
|
assignment = Assignment(None, new_vvar, vvar, ins_addr=ins_addr)
|
|
220
228
|
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
from ailment.block import Block
|
|
6
|
-
from ailment.statement import Statement, Assignment, Store, Call, Return, ConditionalJump
|
|
6
|
+
from ailment.statement import Statement, Assignment, Store, Call, Return, ConditionalJump, DirtyStatement
|
|
7
7
|
from ailment.expression import (
|
|
8
8
|
Register,
|
|
9
9
|
VirtualVariable,
|
|
@@ -14,6 +14,8 @@ from ailment.expression import (
|
|
|
14
14
|
Convert,
|
|
15
15
|
StackBaseOffset,
|
|
16
16
|
ITE,
|
|
17
|
+
VEXCCallExpression,
|
|
18
|
+
DirtyExpression,
|
|
17
19
|
)
|
|
18
20
|
|
|
19
21
|
from angr.engines.light import SimEngineLight, SimEngineLightAILMixin
|
|
@@ -139,10 +141,19 @@ class SimEngineDephiRewriting(
|
|
|
139
141
|
args=stmt.args,
|
|
140
142
|
ret_expr=stmt.ret_expr if new_ret_expr is None else new_ret_expr,
|
|
141
143
|
fp_ret_expr=stmt.fp_ret_expr if new_fp_ret_expr is None else new_fp_ret_expr,
|
|
144
|
+
bits=stmt.bits,
|
|
142
145
|
**stmt.tags,
|
|
143
146
|
)
|
|
144
147
|
return None
|
|
145
148
|
|
|
149
|
+
_handle_CallExpr = _handle_Call
|
|
150
|
+
|
|
151
|
+
def _handle_DirtyStatement(self, stmt: DirtyStatement) -> DirtyStatement | None:
|
|
152
|
+
dirty = self._expr(stmt.dirty)
|
|
153
|
+
if dirty is None or dirty is stmt.dirty:
|
|
154
|
+
return None
|
|
155
|
+
return DirtyStatement(stmt.idx, dirty, **stmt.tags)
|
|
156
|
+
|
|
146
157
|
def _handle_Register(self, expr: Register) -> None:
|
|
147
158
|
return None
|
|
148
159
|
|
|
@@ -243,5 +254,57 @@ class SimEngineDephiRewriting(
|
|
|
243
254
|
)
|
|
244
255
|
return None
|
|
245
256
|
|
|
257
|
+
def _handle_VEXCCallExpression(self, expr: VEXCCallExpression) -> VEXCCallExpression | None:
|
|
258
|
+
new_operands = []
|
|
259
|
+
updated = False
|
|
260
|
+
for o in expr.operands:
|
|
261
|
+
new_o = self._expr(o)
|
|
262
|
+
if new_o is not None:
|
|
263
|
+
updated = True
|
|
264
|
+
new_operands.append(new_o)
|
|
265
|
+
else:
|
|
266
|
+
new_operands.append(o)
|
|
267
|
+
|
|
268
|
+
if updated:
|
|
269
|
+
return VEXCCallExpression(
|
|
270
|
+
expr.idx,
|
|
271
|
+
expr.callee,
|
|
272
|
+
new_operands,
|
|
273
|
+
bits=expr.bits,
|
|
274
|
+
**expr.tags,
|
|
275
|
+
)
|
|
276
|
+
return None
|
|
277
|
+
|
|
278
|
+
def _handle_DirtyExpression(self, expr: DirtyExpression) -> DirtyExpression | None:
|
|
279
|
+
new_operands = []
|
|
280
|
+
updated = False
|
|
281
|
+
for o in expr.operands:
|
|
282
|
+
new_o = self._expr(o)
|
|
283
|
+
if new_o is not None:
|
|
284
|
+
updated = True
|
|
285
|
+
new_operands.append(new_o)
|
|
286
|
+
else:
|
|
287
|
+
new_operands.append(o)
|
|
288
|
+
|
|
289
|
+
new_guard = None
|
|
290
|
+
if expr.guard is not None:
|
|
291
|
+
new_guard = self._expr(expr.guard)
|
|
292
|
+
if new_guard is not None:
|
|
293
|
+
updated = True
|
|
294
|
+
|
|
295
|
+
if updated:
|
|
296
|
+
return DirtyExpression(
|
|
297
|
+
expr.idx,
|
|
298
|
+
expr.callee,
|
|
299
|
+
new_operands,
|
|
300
|
+
guard=new_guard,
|
|
301
|
+
mfx=expr.mfx,
|
|
302
|
+
maddr=expr.maddr,
|
|
303
|
+
msize=expr.msize,
|
|
304
|
+
bits=expr.bits,
|
|
305
|
+
**expr.tags,
|
|
306
|
+
)
|
|
307
|
+
return None
|
|
308
|
+
|
|
246
309
|
def _handle_StackBaseOffset(self, expr: StackBaseOffset) -> None:
|
|
247
310
|
return None
|
|
@@ -105,7 +105,11 @@ class NarrowingInfoExtractor(AILBlockWalkerBase):
|
|
|
105
105
|
def _handle_DirtyExpression(
|
|
106
106
|
self, expr_idx: int, expr: DirtyExpression, stmt_idx: int, stmt: Statement, block: Block | None
|
|
107
107
|
):
|
|
108
|
-
|
|
108
|
+
r = False
|
|
109
|
+
if expr.operands:
|
|
110
|
+
for i, op in enumerate(expr.operands):
|
|
111
|
+
r |= self._handle_expr(i, op, stmt_idx, stmt, block)
|
|
112
|
+
return r
|
|
109
113
|
|
|
110
114
|
def _handle_VEXCCallExpression(
|
|
111
115
|
self, expr_idx: int, expr: VEXCCallExpression, stmt_idx: int, stmt: Statement, block: Block | None
|
|
@@ -18,7 +18,10 @@ class DivSimplifierAILEngine(SimplifierAILEngine):
|
|
|
18
18
|
An AIL pass for the div simplifier
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
@staticmethod
|
|
22
|
+
def _check_divisor(a, b, ndigits=6):
|
|
23
|
+
if b == 0:
|
|
24
|
+
return None
|
|
22
25
|
divisor_1 = 1 + (a // b)
|
|
23
26
|
divisor_2 = int(round(a / float(b), ndigits))
|
|
24
27
|
return divisor_1 if divisor_1 == divisor_2 else None
|