angr 9.2.123__py3-none-manylinux2014_aarch64.whl → 9.2.125__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/__init__.py +9 -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/codecave.py +77 -0
- 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 +58 -2
- angr/analyses/decompiler/condition_processor.py +10 -3
- angr/analyses/decompiler/decompilation_cache.py +2 -0
- angr/analyses/decompiler/decompiler.py +54 -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/__init__.py +3 -0
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +4 -1
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +13 -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/tag_slicer.py +41 -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/constant_derefs.py +2 -2
- 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/patchfinder.py +137 -0
- angr/analyses/pathfinder.py +282 -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/smc.py +159 -0
- angr/analyses/variable_recovery/engine_ail.py +14 -0
- angr/analyses/variable_recovery/engine_base.py +11 -0
- angr/angrdb/models.py +1 -2
- angr/engines/light/engine.py +12 -0
- angr/engines/vex/heavy/heavy.py +2 -0
- angr/exploration_techniques/spiller_db.py +1 -2
- angr/knowledge_plugins/__init__.py +2 -0
- angr/knowledge_plugins/decompilation.py +45 -0
- angr/knowledge_plugins/functions/function.py +4 -0
- angr/knowledge_plugins/functions/function_manager.py +18 -9
- angr/knowledge_plugins/functions/function_parser.py +1 -1
- angr/knowledge_plugins/functions/soot_function.py +1 -0
- angr/knowledge_plugins/key_definitions/atoms.py +8 -0
- angr/misc/ux.py +2 -2
- angr/procedures/definitions/parse_win32json.py +2 -1
- angr/project.py +17 -1
- angr/state_plugins/history.py +6 -4
- 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/bits.py +4 -0
- angr/utils/constants.py +1 -1
- angr/utils/graph.py +15 -0
- angr/utils/tagged_interval_map.py +112 -0
- angr/vaults.py +2 -2
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/METADATA +6 -6
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/RECORD +103 -96
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/WHEEL +1 -1
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/LICENSE +0 -0
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/entry_points.txt +0 -0
- {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
angr/analyses/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pylint:disable=wrong-import-position
|
|
1
|
+
# " pylint:disable=wrong-import-position
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
from .analysis import Analysis, AnalysesHub
|
|
@@ -49,6 +49,10 @@ from .flirt import FlirtAnalysis
|
|
|
49
49
|
from .s_propagator import SPropagatorAnalysis
|
|
50
50
|
from .s_reaching_definitions import SReachingDefinitionsAnalysis
|
|
51
51
|
from .s_liveness import SLivenessAnalysis
|
|
52
|
+
from .codecave import CodeCaveAnalysis
|
|
53
|
+
from .patchfinder import PatchFinderAnalysis
|
|
54
|
+
from .pathfinder import Pathfinder
|
|
55
|
+
from .smc import SelfModifyingCodeAnalysis
|
|
52
56
|
|
|
53
57
|
|
|
54
58
|
__all__ = (
|
|
@@ -101,4 +105,8 @@ __all__ = (
|
|
|
101
105
|
"SPropagatorAnalysis",
|
|
102
106
|
"SReachingDefinitionsAnalysis",
|
|
103
107
|
"SLivenessAnalysis",
|
|
108
|
+
"CodeCaveAnalysis",
|
|
109
|
+
"PatchFinderAnalysis",
|
|
110
|
+
"Pathfinder",
|
|
111
|
+
"SelfModifyingCodeAnalysis",
|
|
104
112
|
)
|
|
@@ -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, []
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import logging
|
|
3
|
+
from enum import Enum, auto
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
from angr.analyses import Analysis, AnalysesHub
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from angr.knowledge_plugins import Function
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
log = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CodeCaveClassification(Enum):
|
|
18
|
+
"""
|
|
19
|
+
Type of code caves.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
ALIGNMENT = auto()
|
|
23
|
+
UNREACHABLE = auto()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class CodeCave:
|
|
28
|
+
"""
|
|
29
|
+
Describes a code cave in a binary.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
func: Function | None
|
|
33
|
+
addr: int
|
|
34
|
+
size: int
|
|
35
|
+
classification: CodeCaveClassification
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CodeCaveAnalysis(Analysis):
|
|
39
|
+
"""
|
|
40
|
+
Best-effort static location of potential vacant code caves for possible code injection:
|
|
41
|
+
- Padding functions
|
|
42
|
+
- Unreachable code
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
codecaves: list[CodeCave]
|
|
46
|
+
|
|
47
|
+
def __init__(self):
|
|
48
|
+
self.codecaves = []
|
|
49
|
+
|
|
50
|
+
if len(self.project.kb.functions) == 0 and self.project.kb.cfgs.get_most_accurate() is None:
|
|
51
|
+
log.warning("Please run CFGFast analysis first, to identify functions")
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
# Alignment functions
|
|
55
|
+
for func in self.project.kb.functions.values():
|
|
56
|
+
if func.is_alignment:
|
|
57
|
+
for block in func.blocks:
|
|
58
|
+
self.codecaves.append(CodeCave(func, block.addr, block.size, CodeCaveClassification.ALIGNMENT))
|
|
59
|
+
|
|
60
|
+
# Unreachable code
|
|
61
|
+
for func in self.project.kb.functions.values():
|
|
62
|
+
if func.is_alignment or func.is_plt or func.is_simprocedure or func.addr in self.project.kb.labels:
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
in_degree = self.project.kb.callgraph.in_degree(func.addr)
|
|
66
|
+
if in_degree == 0 or (
|
|
67
|
+
in_degree == 1
|
|
68
|
+
and self.project.kb.functions[next(self.project.kb.callgraph.predecessors(func.addr))].is_alignment
|
|
69
|
+
):
|
|
70
|
+
for block in func.blocks:
|
|
71
|
+
self.codecaves.append(CodeCave(func, block.addr, block.size, CodeCaveClassification.UNREACHABLE))
|
|
72
|
+
|
|
73
|
+
# FIXME: find dead blocks with argument propagation
|
|
74
|
+
# FIXME: find dead blocks with external coverage info
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
AnalysesHub.register_default("CodeCaves", CodeCaveAnalysis)
|
|
@@ -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]
|
|
@@ -42,6 +42,7 @@ from .optimization_passes import (
|
|
|
42
42
|
OptimizationPassStage,
|
|
43
43
|
RegisterSaveAreaSimplifier,
|
|
44
44
|
StackCanarySimplifier,
|
|
45
|
+
TagSlicer,
|
|
45
46
|
DUPLICATING_OPTS,
|
|
46
47
|
CONDENSING_OPTS,
|
|
47
48
|
)
|
|
@@ -110,6 +111,8 @@ class Clinic(Analysis):
|
|
|
110
111
|
inlined_counts: dict[int, int] | None = None,
|
|
111
112
|
inlining_parents: set[int] | None = None,
|
|
112
113
|
vvar_id_start: int = 0,
|
|
114
|
+
optimization_scratch: dict[str, Any] | None = None,
|
|
115
|
+
desired_variables: set[str] | None = None,
|
|
113
116
|
):
|
|
114
117
|
if not func.normalized and mode == ClinicMode.DECOMPILE:
|
|
115
118
|
raise ValueError("Decompilation must work on normalized function graphs.")
|
|
@@ -124,6 +127,7 @@ class Clinic(Analysis):
|
|
|
124
127
|
self.variable_kb = variable_kb
|
|
125
128
|
self.externs: set[SimMemoryVariable] = set()
|
|
126
129
|
self.data_refs: dict[int, int] = {} # data address to instruction address
|
|
130
|
+
self.optimization_scratch = optimization_scratch if optimization_scratch is not None else {}
|
|
127
131
|
|
|
128
132
|
self._func_graph: networkx.DiGraph | None = None
|
|
129
133
|
self._ail_manager = None
|
|
@@ -152,6 +156,7 @@ class Clinic(Analysis):
|
|
|
152
156
|
self._inline_functions = inline_functions
|
|
153
157
|
self._inlined_counts = {} if inlined_counts is None else inlined_counts
|
|
154
158
|
self._inlining_parents = inlining_parents or ()
|
|
159
|
+
self._desired_variables = desired_variables
|
|
155
160
|
|
|
156
161
|
self._register_save_areas_removed: bool = False
|
|
157
162
|
|
|
@@ -218,6 +223,9 @@ class Clinic(Analysis):
|
|
|
218
223
|
ail_graph = self._inline_child_functions(ail_graph)
|
|
219
224
|
|
|
220
225
|
ail_graph = self._decompilation_simplifications(ail_graph)
|
|
226
|
+
|
|
227
|
+
if self._desired_variables:
|
|
228
|
+
ail_graph = self._slice_variables(ail_graph)
|
|
221
229
|
self.graph = ail_graph
|
|
222
230
|
|
|
223
231
|
def _decompilation_graph_recovery(self):
|
|
@@ -277,6 +285,27 @@ class Clinic(Analysis):
|
|
|
277
285
|
|
|
278
286
|
return ail_graph
|
|
279
287
|
|
|
288
|
+
def _slice_variables(self, ail_graph):
|
|
289
|
+
nodes_index = {(n.addr, n.idx): n for n in ail_graph.nodes()}
|
|
290
|
+
|
|
291
|
+
vfm = self.variable_kb.variables.function_managers[self.function.addr]
|
|
292
|
+
for v_name in self._desired_variables:
|
|
293
|
+
v = next(iter(vv for vv in vfm._unified_variables if vv.name == v_name))
|
|
294
|
+
for va in vfm.get_variable_accesses(v):
|
|
295
|
+
nodes_index[(va.location.block_addr, va.location.block_idx)].statements[va.location.stmt_idx].tags[
|
|
296
|
+
"keep_in_slice"
|
|
297
|
+
] = True
|
|
298
|
+
|
|
299
|
+
a = TagSlicer(
|
|
300
|
+
self.function,
|
|
301
|
+
graph=ail_graph,
|
|
302
|
+
variable_kb=self.variable_kb,
|
|
303
|
+
)
|
|
304
|
+
if a.out_graph:
|
|
305
|
+
# use the new graph
|
|
306
|
+
ail_graph = a.out_graph
|
|
307
|
+
return ail_graph
|
|
308
|
+
|
|
280
309
|
def _inline_child_functions(self, ail_graph):
|
|
281
310
|
for blk in ail_graph.nodes():
|
|
282
311
|
for idx, stmt in enumerate(blk.statements):
|
|
@@ -907,22 +936,31 @@ class Clinic(Analysis):
|
|
|
907
936
|
Convert a VEX block to an AIL block.
|
|
908
937
|
|
|
909
938
|
:param block_node: A BlockNode instance.
|
|
910
|
-
:return:
|
|
939
|
+
:return: A converted AIL block.
|
|
911
940
|
:rtype: ailment.Block
|
|
912
941
|
"""
|
|
913
942
|
|
|
914
943
|
if type(block_node) is not BlockNode:
|
|
915
944
|
return block_node
|
|
916
945
|
|
|
946
|
+
if block_node.size == 0:
|
|
947
|
+
return ailment.Block(block_node.addr, 0, statements=[])
|
|
948
|
+
|
|
917
949
|
block = self.project.factory.block(block_node.addr, block_node.size, cross_insn_opt=False)
|
|
918
950
|
if block.vex.jumpkind not in {"Ijk_Call", "Ijk_Boring", "Ijk_Ret"} and not block.vex.jumpkind.startswith(
|
|
919
951
|
"Ijk_Sys"
|
|
920
952
|
):
|
|
921
953
|
# we don't support lifting this block. use a dummy block instead
|
|
954
|
+
dirty_expr = ailment.Expr.DirtyExpression(
|
|
955
|
+
self._ail_manager.next_atom,
|
|
956
|
+
f"Unsupported jumpkind {block.vex.jumpkind} at address {block_node.addr}",
|
|
957
|
+
[],
|
|
958
|
+
bits=0,
|
|
959
|
+
)
|
|
922
960
|
statements = [
|
|
923
961
|
ailment.Stmt.DirtyStatement(
|
|
924
962
|
self._ail_manager.next_atom(),
|
|
925
|
-
|
|
963
|
+
dirty_expr,
|
|
926
964
|
ins_addr=block_node.addr,
|
|
927
965
|
)
|
|
928
966
|
]
|
|
@@ -1219,6 +1257,7 @@ class Clinic(Analysis):
|
|
|
1219
1257
|
variable_kb=variable_kb,
|
|
1220
1258
|
vvar_id_start=self.vvar_id_start,
|
|
1221
1259
|
entry_node_addr=self.entry_node_addr,
|
|
1260
|
+
scratch=self.optimization_scratch,
|
|
1222
1261
|
**kwargs,
|
|
1223
1262
|
)
|
|
1224
1263
|
if a.out_graph:
|
|
@@ -1256,6 +1295,7 @@ class Clinic(Analysis):
|
|
|
1256
1295
|
ailment.Expr.VirtualVariableCategory.PARAMETER,
|
|
1257
1296
|
oident=arg.reg,
|
|
1258
1297
|
ins_addr=self.function.addr,
|
|
1298
|
+
vex_block_addr=self.function.addr,
|
|
1259
1299
|
)
|
|
1260
1300
|
self.vvar_id_start += 1
|
|
1261
1301
|
arg_vvars[arg_vvar.varid] = arg_vvar, arg
|
|
@@ -1269,6 +1309,7 @@ class Clinic(Analysis):
|
|
|
1269
1309
|
False,
|
|
1270
1310
|
arg_vvar,
|
|
1271
1311
|
ins_addr=self.function.addr,
|
|
1312
|
+
vex_block_addr=self.function.addr,
|
|
1272
1313
|
)
|
|
1273
1314
|
|
|
1274
1315
|
fullreg_dst = ailment.Expr.Register(
|
|
@@ -1277,12 +1318,14 @@ class Clinic(Analysis):
|
|
|
1277
1318
|
basereg_offset,
|
|
1278
1319
|
basereg_size * self.project.arch.byte_width,
|
|
1279
1320
|
ins_addr=self.function.addr,
|
|
1321
|
+
vex_block_addr=self.function.addr,
|
|
1280
1322
|
)
|
|
1281
1323
|
stmt = ailment.Stmt.Assignment(
|
|
1282
1324
|
self._ail_manager.next_atom(),
|
|
1283
1325
|
fullreg_dst,
|
|
1284
1326
|
arg_vvar,
|
|
1285
1327
|
ins_addr=self.function.addr,
|
|
1328
|
+
vex_block_addr=self.function.addr,
|
|
1286
1329
|
)
|
|
1287
1330
|
new_stmts.append(stmt)
|
|
1288
1331
|
|
|
@@ -1313,6 +1356,7 @@ class Clinic(Analysis):
|
|
|
1313
1356
|
ail_graph,
|
|
1314
1357
|
entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
|
|
1315
1358
|
ail_manager=self._ail_manager,
|
|
1359
|
+
ssa_tmps=True,
|
|
1316
1360
|
ssa_stackvars=True,
|
|
1317
1361
|
vvar_id_start=self.vvar_id_start,
|
|
1318
1362
|
)
|
|
@@ -1792,6 +1836,18 @@ class Clinic(Analysis):
|
|
|
1792
1836
|
elif isinstance(expr, ailment.Stmt.Call):
|
|
1793
1837
|
self._link_variables_on_call(variable_manager, global_variables, block, stmt_idx, expr, is_expr=True)
|
|
1794
1838
|
|
|
1839
|
+
elif isinstance(expr, ailment.Expr.VEXCCallExpression):
|
|
1840
|
+
for operand in expr.operands:
|
|
1841
|
+
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, operand)
|
|
1842
|
+
|
|
1843
|
+
elif isinstance(expr, ailment.Expr.DirtyExpression):
|
|
1844
|
+
for operand in expr.operands:
|
|
1845
|
+
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, operand)
|
|
1846
|
+
if expr.maddr:
|
|
1847
|
+
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.maddr)
|
|
1848
|
+
if expr.guard:
|
|
1849
|
+
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.guard)
|
|
1850
|
+
|
|
1795
1851
|
def _function_graph_to_ail_graph(self, func_graph, blocks_by_addr_and_size=None):
|
|
1796
1852
|
if blocks_by_addr_and_size is None:
|
|
1797
1853
|
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
|