angr 9.2.101__py3-none-win_amd64.whl → 9.2.103__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/analysis.py +7 -6
- angr/analyses/calling_convention.py +33 -35
- angr/analyses/cdg.py +2 -4
- angr/analyses/cfg/cfb.py +4 -3
- angr/analyses/cfg/cfg_base.py +14 -14
- angr/analyses/cfg/cfg_emulated.py +3 -4
- angr/analyses/cfg/cfg_fast.py +46 -46
- angr/analyses/cfg/cfg_fast_soot.py +1 -2
- angr/analyses/cfg/cfg_job_base.py +2 -2
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +14 -13
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +5 -5
- angr/analyses/cfg_slice_to_sink/cfg_slice_to_sink.py +3 -3
- angr/analyses/complete_calling_conventions.py +13 -12
- angr/analyses/data_dep/data_dependency_analysis.py +24 -24
- angr/analyses/data_dep/dep_nodes.py +3 -3
- angr/analyses/ddg.py +1 -2
- angr/analyses/decompiler/ail_simplifier.py +35 -34
- angr/analyses/decompiler/block_io_finder.py +20 -20
- angr/analyses/decompiler/block_similarity.py +4 -6
- angr/analyses/decompiler/block_simplifier.py +17 -16
- angr/analyses/decompiler/callsite_maker.py +25 -10
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -3
- angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +2 -4
- angr/analyses/decompiler/clinic.py +250 -45
- angr/analyses/decompiler/condition_processor.py +15 -8
- angr/analyses/decompiler/decompilation_cache.py +7 -7
- angr/analyses/decompiler/decompilation_options.py +4 -4
- angr/analyses/decompiler/decompiler.py +19 -15
- angr/analyses/decompiler/expression_counters.py +10 -9
- angr/analyses/decompiler/goto_manager.py +2 -4
- angr/analyses/decompiler/graph_region.py +9 -9
- angr/analyses/decompiler/jump_target_collector.py +1 -2
- angr/analyses/decompiler/optimization_passes/__init__.py +4 -3
- angr/analyses/decompiler/optimization_passes/code_motion.py +5 -6
- angr/analyses/decompiler/optimization_passes/const_derefs.py +4 -4
- angr/analyses/decompiler/optimization_passes/deadblock_remover.py +73 -0
- angr/analyses/decompiler/optimization_passes/engine_base.py +25 -3
- angr/analyses/decompiler/optimization_passes/expr_op_swapper.py +6 -5
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +2 -2
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +3 -0
- angr/analyses/decompiler/optimization_passes/ite_expr_converter.py +2 -2
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +17 -17
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +12 -13
- angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +25 -21
- angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py +3 -3
- angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +1 -2
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +7 -7
- angr/analyses/decompiler/optimization_passes/spilled_register_finder.py +18 -0
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +2 -3
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +1 -2
- angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/__init__.py +4 -3
- angr/analyses/decompiler/peephole_optimizations/base.py +13 -15
- angr/analyses/decompiler/peephole_optimizations/bswap.py +1 -3
- angr/analyses/decompiler/peephole_optimizations/cmpord_rewriter.py +72 -0
- angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +1 -2
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +5 -10
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +3 -4
- angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +7 -10
- angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +2 -3
- angr/analyses/decompiler/peephole_optimizations/sar_to_signed_div.py +1 -2
- angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py +4 -4
- angr/analyses/decompiler/redundant_label_remover.py +4 -5
- angr/analyses/decompiler/region_identifier.py +4 -5
- angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py +1 -2
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +19 -20
- angr/analyses/decompiler/region_simplifiers/goto.py +2 -3
- angr/analyses/decompiler/region_simplifiers/loop.py +1 -2
- angr/analyses/decompiler/region_simplifiers/node_address_finder.py +1 -2
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +1 -3
- angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +19 -19
- angr/analyses/decompiler/return_maker.py +1 -2
- angr/analyses/decompiler/structured_codegen/base.py +5 -6
- angr/analyses/decompiler/structured_codegen/c.py +39 -38
- angr/analyses/decompiler/structuring/__init__.py +1 -1
- angr/analyses/decompiler/structuring/dream.py +17 -16
- angr/analyses/decompiler/structuring/phoenix.py +45 -46
- angr/analyses/decompiler/structuring/recursive_structurer.py +4 -4
- angr/analyses/decompiler/structuring/structurer_base.py +16 -15
- angr/analyses/decompiler/structuring/structurer_nodes.py +10 -9
- angr/analyses/decompiler/utils.py +17 -16
- angr/analyses/disassembly.py +7 -6
- angr/analyses/flirt.py +9 -9
- angr/analyses/forward_analysis/forward_analysis.py +15 -14
- angr/analyses/forward_analysis/visitors/function_graph.py +1 -2
- angr/analyses/forward_analysis/visitors/graph.py +16 -15
- angr/analyses/propagator/engine_ail.py +30 -26
- angr/analyses/propagator/outdated_definition_walker.py +8 -7
- angr/analyses/propagator/propagator.py +11 -13
- angr/analyses/proximity_graph.py +21 -21
- angr/analyses/reaching_definitions/__init__.py +3 -3
- angr/analyses/reaching_definitions/call_trace.py +3 -6
- angr/analyses/reaching_definitions/dep_graph.py +41 -48
- angr/analyses/reaching_definitions/engine_ail.py +11 -5
- angr/analyses/reaching_definitions/engine_vex.py +9 -8
- angr/analyses/reaching_definitions/function_handler.py +51 -34
- angr/analyses/reaching_definitions/heap_allocator.py +3 -4
- angr/analyses/reaching_definitions/rd_initializer.py +8 -8
- angr/analyses/reaching_definitions/rd_state.py +57 -58
- angr/analyses/reaching_definitions/reaching_definitions.py +18 -17
- angr/analyses/reaching_definitions/subject.py +2 -3
- angr/analyses/stack_pointer_tracker.py +15 -6
- angr/analyses/typehoon/dfa.py +4 -4
- angr/analyses/typehoon/simple_solver.py +48 -52
- angr/analyses/typehoon/translator.py +3 -6
- angr/analyses/typehoon/typeconsts.py +13 -14
- angr/analyses/typehoon/typehoon.py +9 -9
- angr/analyses/typehoon/typevars.py +18 -17
- angr/analyses/variable_recovery/engine_ail.py +5 -5
- angr/analyses/variable_recovery/engine_base.py +25 -21
- angr/analyses/variable_recovery/irsb_scanner.py +8 -9
- angr/analyses/variable_recovery/variable_recovery.py +1 -2
- angr/analyses/variable_recovery/variable_recovery_base.py +14 -13
- angr/analyses/variable_recovery/variable_recovery_fast.py +8 -8
- angr/analyses/veritesting.py +1 -2
- angr/analyses/vfg.py +57 -56
- angr/analyses/xrefs.py +1 -2
- angr/angrdb/db.py +7 -7
- angr/angrdb/serializers/kb.py +16 -13
- angr/angrdb/serializers/loader.py +1 -2
- angr/angrdb/serializers/structured_code.py +2 -2
- angr/annocfg.py +1 -2
- angr/block.py +16 -6
- angr/calling_conventions.py +27 -27
- angr/code_location.py +8 -8
- angr/codenode.py +1 -2
- angr/concretization_strategies/max.py +1 -3
- angr/distributed/server.py +1 -3
- angr/distributed/worker.py +1 -2
- angr/engines/engine.py +2 -3
- angr/engines/light/engine.py +4 -4
- angr/engines/pcode/behavior.py +20 -2
- angr/engines/pcode/emulate.py +1 -1
- angr/engines/pcode/engine.py +7 -7
- angr/engines/pcode/lifter.py +78 -77
- angr/engines/vex/claripy/ccall.py +1 -2
- angr/engines/vex/claripy/datalayer.py +1 -2
- angr/engines/vex/light/light.py +1 -2
- angr/exploration_techniques/tracer.py +4 -4
- angr/factory.py +12 -15
- angr/flirt/__init__.py +8 -8
- angr/flirt/build_sig.py +2 -3
- angr/keyed_region.py +2 -2
- angr/knowledge_base/knowledge_base.py +3 -3
- angr/knowledge_plugins/callsite_prototypes.py +4 -6
- angr/knowledge_plugins/cfg/cfg_manager.py +19 -6
- angr/knowledge_plugins/cfg/cfg_model.py +26 -27
- angr/knowledge_plugins/cfg/cfg_node.py +2 -2
- angr/knowledge_plugins/cfg/indirect_jump.py +6 -8
- angr/knowledge_plugins/cfg/memory_data.py +8 -9
- angr/knowledge_plugins/custom_strings.py +1 -3
- angr/knowledge_plugins/debug_variables.py +2 -2
- angr/knowledge_plugins/functions/function.py +21 -22
- angr/knowledge_plugins/functions/function_manager.py +5 -5
- angr/knowledge_plugins/indirect_jumps.py +1 -3
- angr/knowledge_plugins/key_definitions/atoms.py +7 -7
- angr/knowledge_plugins/key_definitions/definition.py +14 -14
- angr/knowledge_plugins/key_definitions/environment.py +5 -7
- angr/knowledge_plugins/key_definitions/heap_address.py +1 -3
- angr/knowledge_plugins/key_definitions/key_definition_manager.py +3 -2
- angr/knowledge_plugins/key_definitions/live_definitions.py +60 -59
- angr/knowledge_plugins/key_definitions/liveness.py +16 -16
- angr/knowledge_plugins/key_definitions/rd_model.py +15 -15
- angr/knowledge_plugins/key_definitions/uses.py +11 -11
- angr/knowledge_plugins/patches.py +4 -8
- angr/knowledge_plugins/propagations/prop_value.py +10 -9
- angr/knowledge_plugins/propagations/propagation_manager.py +3 -5
- angr/knowledge_plugins/propagations/propagation_model.py +9 -9
- angr/knowledge_plugins/propagations/states.py +52 -22
- angr/knowledge_plugins/structured_code/manager.py +2 -2
- angr/knowledge_plugins/sync/sync_controller.py +3 -3
- angr/knowledge_plugins/variables/variable_access.py +4 -4
- angr/knowledge_plugins/variables/variable_manager.py +56 -39
- angr/knowledge_plugins/xrefs/xref.py +9 -11
- angr/knowledge_plugins/xrefs/xref_manager.py +3 -4
- angr/lib/angr_native.dll +0 -0
- angr/misc/ansi.py +1 -2
- angr/misc/autoimport.py +3 -3
- angr/misc/plugins.py +9 -9
- angr/procedures/definitions/__init__.py +16 -16
- angr/procedures/definitions/linux_kernel.py +1 -1
- angr/procedures/definitions/parse_win32json.py +1 -1
- angr/procedures/java_jni/__init__.py +1 -1
- angr/procedures/java_jni/array_operations.py +1 -2
- angr/procedures/java_jni/method_calls.py +1 -2
- angr/procedures/posix/inet_ntoa.py +1 -2
- angr/procedures/stubs/format_parser.py +3 -3
- angr/project.py +13 -11
- angr/sim_manager.py +12 -12
- angr/sim_procedure.py +7 -3
- angr/sim_state.py +2 -2
- angr/sim_type.py +60 -45
- angr/sim_variable.py +5 -5
- angr/simos/simos.py +1 -2
- angr/simos/userland.py +1 -2
- angr/state_plugins/callstack.py +3 -2
- angr/state_plugins/history.py +1 -2
- angr/state_plugins/solver.py +34 -34
- angr/storage/memory_mixins/__init__.py +4 -3
- angr/storage/memory_mixins/actions_mixin.py +1 -3
- angr/storage/memory_mixins/address_concretization_mixin.py +1 -3
- angr/storage/memory_mixins/convenient_mappings_mixin.py +3 -4
- angr/storage/memory_mixins/default_filler_mixin.py +1 -1
- angr/storage/memory_mixins/label_merger_mixin.py +2 -2
- angr/storage/memory_mixins/multi_value_merger_mixin.py +4 -3
- angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +9 -8
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +12 -11
- angr/storage/memory_mixins/paged_memory/pages/cooperation.py +8 -8
- angr/storage/memory_mixins/paged_memory/pages/history_tracking_mixin.py +2 -3
- angr/storage/memory_mixins/paged_memory/pages/list_page.py +10 -11
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +11 -10
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +18 -17
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +12 -11
- angr/storage/memory_mixins/regioned_memory/abstract_address_descriptor.py +3 -3
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +3 -2
- angr/storage/memory_mixins/regioned_memory/region_data.py +1 -2
- angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +2 -2
- angr/storage/memory_mixins/regioned_memory/regioned_address_concretization_mixin.py +3 -3
- angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +18 -21
- angr/storage/memory_mixins/size_resolution_mixin.py +1 -2
- angr/storage/memory_mixins/symbolic_merger_mixin.py +3 -2
- angr/storage/memory_mixins/top_merger_mixin.py +3 -2
- angr/storage/memory_object.py +2 -4
- angr/utils/algo.py +3 -2
- angr/utils/dynamic_dictlist.py +5 -5
- angr/utils/formatting.py +4 -4
- angr/utils/funcid.py +1 -2
- angr/utils/graph.py +5 -6
- angr/utils/library.py +5 -5
- angr/utils/mp.py +5 -4
- angr/utils/segment_list.py +3 -4
- angr/utils/typing.py +3 -2
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/METADATA +9 -11
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/RECORD +240 -237
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/LICENSE +0 -0
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/WHEEL +0 -0
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/entry_points.txt +0 -0
- {angr-9.2.101.dist-info → angr-9.2.103.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
import copy
|
|
2
3
|
from collections import defaultdict, namedtuple
|
|
3
4
|
import logging
|
|
4
5
|
import enum
|
|
5
6
|
from dataclasses import dataclass
|
|
6
|
-
from typing import
|
|
7
|
+
from typing import Any, NamedTuple, TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from collections.abc import Iterable
|
|
7
10
|
|
|
8
11
|
import networkx
|
|
9
12
|
import capstone
|
|
@@ -26,6 +29,7 @@ from ...sim_type import (
|
|
|
26
29
|
SimTypeFloat,
|
|
27
30
|
SimTypePointer,
|
|
28
31
|
)
|
|
32
|
+
from ..stack_pointer_tracker import Register, OffsetVal
|
|
29
33
|
from ...sim_variable import SimVariable, SimStackVariable, SimRegisterVariable, SimMemoryVariable
|
|
30
34
|
from ...knowledge_plugins.key_definitions.constants import OP_BEFORE
|
|
31
35
|
from ...procedures.stubs.UnresolvableCallTarget import UnresolvableCallTarget
|
|
@@ -39,6 +43,8 @@ from .optimization_passes import (
|
|
|
39
43
|
get_default_optimization_passes,
|
|
40
44
|
OptimizationPassStage,
|
|
41
45
|
RegisterSaveAreaSimplifier,
|
|
46
|
+
StackCanarySimplifier,
|
|
47
|
+
SpilledRegisterFinder,
|
|
42
48
|
DUPLICATING_OPTS,
|
|
43
49
|
CONDENSING_OPTS,
|
|
44
50
|
)
|
|
@@ -92,15 +98,19 @@ class Clinic(Analysis):
|
|
|
92
98
|
insert_labels=True,
|
|
93
99
|
optimization_passes=None,
|
|
94
100
|
cfg=None,
|
|
95
|
-
peephole_optimizations:
|
|
96
|
-
Iterable[
|
|
97
|
-
|
|
98
|
-
must_struct:
|
|
101
|
+
peephole_optimizations: None | (
|
|
102
|
+
Iterable[type[PeepholeOptimizationStmtBase] | type[PeepholeOptimizationExprBase]]
|
|
103
|
+
) = None, # pylint:disable=line-too-long
|
|
104
|
+
must_struct: set[str] | None = None,
|
|
99
105
|
variable_kb=None,
|
|
100
106
|
reset_variable_names=False,
|
|
101
107
|
rewrite_ites_to_diamonds=True,
|
|
102
|
-
cache:
|
|
108
|
+
cache: DecompilationCache | None = None,
|
|
103
109
|
mode: ClinicMode = ClinicMode.DECOMPILE,
|
|
110
|
+
sp_shift: int = 0,
|
|
111
|
+
inline_functions: set[Function] | None = frozenset(),
|
|
112
|
+
inlined_counts: dict[int, int] | None = None,
|
|
113
|
+
inlining_parents: set[int] | None = None,
|
|
104
114
|
):
|
|
105
115
|
if not func.normalized and mode == ClinicMode.DECOMPILE:
|
|
106
116
|
raise ValueError("Decompilation must work on normalized function graphs.")
|
|
@@ -108,14 +118,14 @@ class Clinic(Analysis):
|
|
|
108
118
|
self.function = func
|
|
109
119
|
|
|
110
120
|
self.graph = None
|
|
111
|
-
self.cc_graph:
|
|
112
|
-
self.unoptimized_graph:
|
|
121
|
+
self.cc_graph: networkx.DiGraph | None = None
|
|
122
|
+
self.unoptimized_graph: networkx.DiGraph | None = None
|
|
113
123
|
self.arg_list = None
|
|
114
124
|
self.variable_kb = variable_kb
|
|
115
|
-
self.externs:
|
|
116
|
-
self.data_refs:
|
|
125
|
+
self.externs: set[SimMemoryVariable] = set()
|
|
126
|
+
self.data_refs: dict[int, int] = {} # data address to instruction address
|
|
117
127
|
|
|
118
|
-
self._func_graph:
|
|
128
|
+
self._func_graph: networkx.DiGraph | None = None
|
|
119
129
|
self._ail_manager = None
|
|
120
130
|
self._blocks_by_addr_and_size = {}
|
|
121
131
|
|
|
@@ -124,15 +134,22 @@ class Clinic(Analysis):
|
|
|
124
134
|
self._remove_dead_memdefs = remove_dead_memdefs
|
|
125
135
|
self._exception_edges = exception_edges
|
|
126
136
|
self._sp_tracker_track_memory = sp_tracker_track_memory
|
|
127
|
-
self._cfg:
|
|
137
|
+
self._cfg: CFGModel | None = cfg
|
|
128
138
|
self.peephole_optimizations = peephole_optimizations
|
|
129
139
|
self._must_struct = must_struct
|
|
130
140
|
self._reset_variable_names = reset_variable_names
|
|
131
141
|
self._rewrite_ites_to_diamonds = rewrite_ites_to_diamonds
|
|
132
|
-
self.reaching_definitions:
|
|
142
|
+
self.reaching_definitions: ReachingDefinitionsAnalysis | None = None
|
|
133
143
|
self._cache = cache
|
|
134
144
|
self._mode = mode
|
|
135
145
|
|
|
146
|
+
# inlining help
|
|
147
|
+
self._sp_shift = sp_shift
|
|
148
|
+
self._max_stack_depth = 0
|
|
149
|
+
self._inline_functions = inline_functions
|
|
150
|
+
self._inlined_counts = {} if inlined_counts is None else inlined_counts
|
|
151
|
+
self._inlining_parents = inlining_parents or ()
|
|
152
|
+
|
|
136
153
|
self._register_save_areas_removed: bool = False
|
|
137
154
|
|
|
138
155
|
self._new_block_addrs = set()
|
|
@@ -190,6 +207,18 @@ class Clinic(Analysis):
|
|
|
190
207
|
#
|
|
191
208
|
|
|
192
209
|
def _analyze_for_decompiling(self):
|
|
210
|
+
if not (ail_graph := self._decompilation_graph_recovery()):
|
|
211
|
+
return
|
|
212
|
+
ail_graph = self._decompilation_fixups(ail_graph)
|
|
213
|
+
|
|
214
|
+
if self._inline_functions:
|
|
215
|
+
self._max_stack_depth += self.calculate_stack_depth()
|
|
216
|
+
ail_graph = self._inline_child_functions(ail_graph)
|
|
217
|
+
|
|
218
|
+
ail_graph = self._decompilation_simplifications(ail_graph)
|
|
219
|
+
self.graph = ail_graph
|
|
220
|
+
|
|
221
|
+
def _decompilation_graph_recovery(self):
|
|
193
222
|
is_pcode_arch = ":" in self.project.arch.name
|
|
194
223
|
|
|
195
224
|
# Set up the function graph according to configurations
|
|
@@ -202,7 +231,7 @@ class Clinic(Analysis):
|
|
|
202
231
|
|
|
203
232
|
# if the graph is empty, don't continue
|
|
204
233
|
if not self._func_graph:
|
|
205
|
-
return
|
|
234
|
+
return None
|
|
206
235
|
|
|
207
236
|
# Make sure calling conventions of all functions that the current function calls have been recovered
|
|
208
237
|
if not is_pcode_arch:
|
|
@@ -212,16 +241,16 @@ class Clinic(Analysis):
|
|
|
212
241
|
# initialize the AIL conversion manager
|
|
213
242
|
self._ail_manager = ailment.Manager(arch=self.project.arch)
|
|
214
243
|
|
|
215
|
-
# Track stack pointers
|
|
216
|
-
self._update_progress(15.0, text="Tracking stack pointers")
|
|
217
|
-
spt = self._track_stack_pointers()
|
|
218
|
-
|
|
219
244
|
# Convert VEX blocks to AIL blocks and then simplify them
|
|
220
245
|
|
|
221
246
|
self._update_progress(20.0, text="Converting VEX to AIL")
|
|
222
247
|
self._convert_all()
|
|
223
248
|
|
|
224
|
-
|
|
249
|
+
return self._make_ailgraph()
|
|
250
|
+
|
|
251
|
+
def _decompilation_fixups(self, ail_graph):
|
|
252
|
+
is_pcode_arch = ":" in self.project.arch.name
|
|
253
|
+
|
|
225
254
|
if self._rewrite_ites_to_diamonds:
|
|
226
255
|
self._rewrite_ite_expressions(ail_graph)
|
|
227
256
|
self._remove_redundant_jump_blocks(ail_graph)
|
|
@@ -244,6 +273,127 @@ class Clinic(Analysis):
|
|
|
244
273
|
self._update_progress(29.0, text="Recovering calling conventions (AIL mode)")
|
|
245
274
|
self._recover_calling_conventions(func_graph=ail_graph)
|
|
246
275
|
|
|
276
|
+
return ail_graph
|
|
277
|
+
|
|
278
|
+
def _inline_child_functions(self, ail_graph):
|
|
279
|
+
for blk in ail_graph.nodes():
|
|
280
|
+
for idx, stmt in enumerate(blk.statements):
|
|
281
|
+
if isinstance(stmt, ailment.Stmt.Call) and isinstance(stmt.target, ailment.Expr.Const):
|
|
282
|
+
callee = self.function._function_manager.function(stmt.target.value)
|
|
283
|
+
if (
|
|
284
|
+
callee.addr == self.function.addr
|
|
285
|
+
or callee.addr in self._inlining_parents
|
|
286
|
+
or callee not in self._inline_functions
|
|
287
|
+
or callee.is_plt
|
|
288
|
+
or callee.is_simprocedure
|
|
289
|
+
):
|
|
290
|
+
continue
|
|
291
|
+
|
|
292
|
+
ail_graph = self._inline_call(ail_graph, blk, idx, callee)
|
|
293
|
+
return ail_graph
|
|
294
|
+
|
|
295
|
+
def _inline_call(self, ail_graph, caller_block, call_idx, callee):
|
|
296
|
+
callee_clinic = self.project.analyses.Clinic(
|
|
297
|
+
callee,
|
|
298
|
+
mode=ClinicMode.DECOMPILE,
|
|
299
|
+
inline_functions=self._inline_functions,
|
|
300
|
+
inlining_parents=self._inlining_parents + (self.function.addr,),
|
|
301
|
+
inlined_counts=self._inlined_counts,
|
|
302
|
+
optimization_passes=[StackCanarySimplifier, SpilledRegisterFinder],
|
|
303
|
+
sp_shift=self._max_stack_depth,
|
|
304
|
+
)
|
|
305
|
+
self._max_stack_depth = callee_clinic._max_stack_depth
|
|
306
|
+
callee_graph = callee_clinic.copy_graph()
|
|
307
|
+
|
|
308
|
+
# uniquely mark all the blocks in case of duplicates (e.g., foo(); foo();)
|
|
309
|
+
self._inlined_counts.setdefault(callee.addr, 0)
|
|
310
|
+
for blk in callee_graph.nodes():
|
|
311
|
+
blk.idx = self._inlined_counts[callee.addr]
|
|
312
|
+
self._inlined_counts[callee.addr] += 1
|
|
313
|
+
|
|
314
|
+
# figure out where the callee should start at and return to
|
|
315
|
+
callee_start = next(n for n in callee_graph if n.addr == callee.addr)
|
|
316
|
+
caller_successors = list(ail_graph.out_edges(caller_block, data=True))
|
|
317
|
+
assert len(caller_successors) == 1
|
|
318
|
+
caller_successor = caller_successors[0][1]
|
|
319
|
+
ail_graph.remove_edge(caller_block, caller_successor)
|
|
320
|
+
|
|
321
|
+
# update all callee return nodes with caller successor
|
|
322
|
+
# and rewrite pseudoreg-tagged spills to actually use pseudoregs
|
|
323
|
+
ail_graph = networkx.union(ail_graph, callee_graph)
|
|
324
|
+
for blk in callee_graph.nodes():
|
|
325
|
+
for idx, stmt in enumerate(list(blk.statements)):
|
|
326
|
+
if isinstance(stmt, ailment.Stmt.Return):
|
|
327
|
+
blk.statements[idx] = ailment.Stmt.Jump(
|
|
328
|
+
None,
|
|
329
|
+
ailment.Expr.Const(None, None, caller_successor.addr, self.project.arch.bits),
|
|
330
|
+
caller_successor.idx,
|
|
331
|
+
**blk.statements[idx].tags,
|
|
332
|
+
)
|
|
333
|
+
blk.statements.pop(idx)
|
|
334
|
+
ail_graph.add_edge(blk, caller_successor)
|
|
335
|
+
break
|
|
336
|
+
if "pseudoreg" in stmt.tags and isinstance(stmt, ailment.Stmt.Store):
|
|
337
|
+
new_stmt = ailment.Stmt.Assignment(
|
|
338
|
+
stmt.idx, ailment.Expr.Register(None, None, stmt.pseudoreg, stmt.size * 8), stmt.data
|
|
339
|
+
)
|
|
340
|
+
new_stmt.tags.update(stmt.tags)
|
|
341
|
+
new_stmt.tags.pop("pseudoreg")
|
|
342
|
+
blk.statements[idx] = new_stmt
|
|
343
|
+
if "pseudoreg" in stmt.tags and isinstance(stmt, ailment.Stmt.Assignment):
|
|
344
|
+
new_stmt = ailment.Stmt.Assignment(
|
|
345
|
+
stmt.idx, stmt.dst, ailment.Expr.Register(None, None, stmt.pseudoreg, stmt.src.size * 8)
|
|
346
|
+
)
|
|
347
|
+
new_stmt.tags.update(stmt.tags)
|
|
348
|
+
new_stmt.tags.pop("pseudoreg")
|
|
349
|
+
blk.statements[idx] = new_stmt
|
|
350
|
+
|
|
351
|
+
# update the call edge
|
|
352
|
+
caller_block.statements[call_idx] = ailment.Stmt.Jump(
|
|
353
|
+
None,
|
|
354
|
+
ailment.Expr.Const(None, None, callee.addr, self.project.arch.bits),
|
|
355
|
+
callee_start.idx,
|
|
356
|
+
**caller_block.statements[call_idx].tags,
|
|
357
|
+
)
|
|
358
|
+
if (
|
|
359
|
+
isinstance(caller_block.statements[call_idx - 2], ailment.Stmt.Store)
|
|
360
|
+
and caller_block.statements[call_idx - 2].data.value == caller_successor.addr
|
|
361
|
+
):
|
|
362
|
+
# don't push the return address
|
|
363
|
+
caller_block.statements.pop(call_idx - 5) # t6 = rsp<8>
|
|
364
|
+
caller_block.statements.pop(call_idx - 5) # t5 = (t6 - 0x8<64>)
|
|
365
|
+
caller_block.statements.pop(call_idx - 5) # rsp<8> = t5
|
|
366
|
+
caller_block.statements.pop(
|
|
367
|
+
call_idx - 5
|
|
368
|
+
) # STORE(addr=t5, data=0x40121b<64>, size=8, endness=Iend_LE, guard=None)
|
|
369
|
+
caller_block.statements.pop(call_idx - 5) # t7 = (t5 - 0x80<64>) <- wtf is this??
|
|
370
|
+
elif (
|
|
371
|
+
isinstance(caller_block.statements[call_idx - 1], ailment.Stmt.Store)
|
|
372
|
+
and caller_block.statements[call_idx - 1].addr.base == "stack_base"
|
|
373
|
+
and caller_block.statements[call_idx - 1].data.value == caller_successor.addr
|
|
374
|
+
):
|
|
375
|
+
caller_block.statements.pop(call_idx - 1) # s_10 =L 0x401225<64><8>
|
|
376
|
+
ail_graph.add_edge(caller_block, callee_start)
|
|
377
|
+
|
|
378
|
+
return ail_graph
|
|
379
|
+
|
|
380
|
+
def calculate_stack_depth(self):
|
|
381
|
+
# we need to reserve space for our own stack
|
|
382
|
+
spt = self._track_stack_pointers()
|
|
383
|
+
stack_offsets = spt.offsets_for(self.project.arch.sp_offset)
|
|
384
|
+
if max(stack_offsets) > 2 ** (self.project.arch.bits - 1):
|
|
385
|
+
# why is this unsigned...
|
|
386
|
+
depth = min(s for s in stack_offsets if s > 2 ** (self.project.arch.bits - 1)) - 2**self.project.arch.bits
|
|
387
|
+
else:
|
|
388
|
+
depth = min(stack_offsets)
|
|
389
|
+
|
|
390
|
+
if spt.inconsistent_for(self.project.arch.sp_offset):
|
|
391
|
+
l.warning("Inconsistency found during stack pointer tracking. Stack depth may be incorrect.")
|
|
392
|
+
depth -= 0x1000
|
|
393
|
+
|
|
394
|
+
return depth
|
|
395
|
+
|
|
396
|
+
def _decompilation_simplifications(self, ail_graph):
|
|
247
397
|
# Make returns
|
|
248
398
|
self._update_progress(30.0, text="Making return sites")
|
|
249
399
|
if self.function.prototype is None or not isinstance(self.function.prototype.returnty, SimTypeBottom):
|
|
@@ -262,7 +412,11 @@ class Clinic(Analysis):
|
|
|
262
412
|
)
|
|
263
413
|
|
|
264
414
|
# cached block-level reaching definition analysis results and propagator results
|
|
265
|
-
block_simplification_cache:
|
|
415
|
+
block_simplification_cache: dict[ailment.Block, NamedTuple] | None = {}
|
|
416
|
+
|
|
417
|
+
# Track stack pointers
|
|
418
|
+
self._update_progress(15.0, text="Tracking stack pointers")
|
|
419
|
+
spt = self._track_stack_pointers()
|
|
266
420
|
|
|
267
421
|
# Simplify blocks
|
|
268
422
|
# we never remove dead memory definitions before making callsites. otherwise stack arguments may go missing
|
|
@@ -373,11 +527,11 @@ class Clinic(Analysis):
|
|
|
373
527
|
# remove empty nodes from the graph
|
|
374
528
|
ail_graph = self.remove_empty_nodes(ail_graph)
|
|
375
529
|
|
|
376
|
-
self.graph = ail_graph
|
|
377
530
|
self.arg_list = arg_list
|
|
378
531
|
self.variable_kb = variable_kb
|
|
379
|
-
self.cc_graph = self.copy_graph()
|
|
532
|
+
self.cc_graph = self.copy_graph(ail_graph)
|
|
380
533
|
self.externs = self._collect_externs(ail_graph, variable_kb)
|
|
534
|
+
return ail_graph
|
|
381
535
|
|
|
382
536
|
def _analyze_for_data_refs(self):
|
|
383
537
|
# Set up the function graph according to configurations
|
|
@@ -404,6 +558,20 @@ class Clinic(Analysis):
|
|
|
404
558
|
self._update_progress(20.0, text="Converting VEX to AIL")
|
|
405
559
|
self._convert_all()
|
|
406
560
|
|
|
561
|
+
# there must be at least one Load or one Store
|
|
562
|
+
found_load_or_store = False
|
|
563
|
+
for ail_block in self._blocks_by_addr_and_size.values():
|
|
564
|
+
for stmt in ail_block.statements:
|
|
565
|
+
if isinstance(stmt, ailment.Stmt.Store):
|
|
566
|
+
found_load_or_store = True
|
|
567
|
+
break
|
|
568
|
+
if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.Load):
|
|
569
|
+
found_load_or_store = True
|
|
570
|
+
break
|
|
571
|
+
if not found_load_or_store:
|
|
572
|
+
self.data_refs = {}
|
|
573
|
+
return
|
|
574
|
+
|
|
407
575
|
ail_graph = self._make_ailgraph()
|
|
408
576
|
self._remove_redundant_jump_blocks(ail_graph)
|
|
409
577
|
|
|
@@ -420,7 +588,7 @@ class Clinic(Analysis):
|
|
|
420
588
|
)
|
|
421
589
|
|
|
422
590
|
# cached block-level reaching definition analysis results and propagator results
|
|
423
|
-
block_simplification_cache:
|
|
591
|
+
block_simplification_cache: dict[ailment.Block, NamedTuple] | None = {}
|
|
424
592
|
|
|
425
593
|
# Simplify blocks
|
|
426
594
|
# we never remove dead memory definitions before making callsites. otherwise stack arguments may go missing
|
|
@@ -438,6 +606,8 @@ class Clinic(Analysis):
|
|
|
438
606
|
unify_variables=False,
|
|
439
607
|
narrow_expressions=False,
|
|
440
608
|
fold_callexprs_into_conditions=False,
|
|
609
|
+
rewrite_ccalls=False,
|
|
610
|
+
max_iterations=1,
|
|
441
611
|
)
|
|
442
612
|
|
|
443
613
|
# clear _blocks_by_addr_and_size so no one can use it again
|
|
@@ -449,7 +619,7 @@ class Clinic(Analysis):
|
|
|
449
619
|
self.variable_kb = None
|
|
450
620
|
self.cc_graph = None
|
|
451
621
|
self.externs = None
|
|
452
|
-
self.data_refs:
|
|
622
|
+
self.data_refs: dict[int, list[DataRefDesc]] = self._collect_data_refs(ail_graph)
|
|
453
623
|
|
|
454
624
|
@staticmethod
|
|
455
625
|
def _copy_graph(graph: networkx.DiGraph) -> networkx.DiGraph:
|
|
@@ -475,8 +645,8 @@ class Clinic(Analysis):
|
|
|
475
645
|
graph_copy.add_edge(new_src, new_dst, **data)
|
|
476
646
|
return graph_copy
|
|
477
647
|
|
|
478
|
-
def copy_graph(self) -> networkx.DiGraph:
|
|
479
|
-
return self._copy_graph(self.graph)
|
|
648
|
+
def copy_graph(self, graph=None) -> networkx.DiGraph:
|
|
649
|
+
return self._copy_graph(graph or self.graph)
|
|
480
650
|
|
|
481
651
|
@timethis
|
|
482
652
|
def _set_function_graph(self):
|
|
@@ -618,14 +788,27 @@ class Clinic(Analysis):
|
|
|
618
788
|
"""
|
|
619
789
|
|
|
620
790
|
regs = {self.project.arch.sp_offset}
|
|
791
|
+
initial_reg_values = {
|
|
792
|
+
self.project.arch.sp_offset: OffsetVal(
|
|
793
|
+
Register(self.project.arch.sp_offset, self.project.arch.bits), self._sp_shift
|
|
794
|
+
)
|
|
795
|
+
}
|
|
621
796
|
if hasattr(self.project.arch, "bp_offset") and self.project.arch.bp_offset is not None:
|
|
622
797
|
regs.add(self.project.arch.bp_offset)
|
|
798
|
+
initial_reg_values[self.project.arch.bp_offset] = OffsetVal(
|
|
799
|
+
Register(self.project.arch.bp_offset, self.project.arch.bits), self._sp_shift
|
|
800
|
+
)
|
|
623
801
|
|
|
624
802
|
regs |= self._find_regs_compared_against_sp(self._func_graph)
|
|
625
803
|
|
|
626
804
|
spt = self.project.analyses.StackPointerTracker(
|
|
627
|
-
self.function,
|
|
805
|
+
self.function,
|
|
806
|
+
regs,
|
|
807
|
+
track_memory=self._sp_tracker_track_memory,
|
|
808
|
+
cross_insn_opt=False,
|
|
809
|
+
initial_reg_values=initial_reg_values,
|
|
628
810
|
)
|
|
811
|
+
|
|
629
812
|
if spt.inconsistent_for(self.project.arch.sp_offset):
|
|
630
813
|
l.warning("Inconsistency found during stack pointer tracking. Decompilation results might be incorrect.")
|
|
631
814
|
return spt
|
|
@@ -642,6 +825,18 @@ class Clinic(Analysis):
|
|
|
642
825
|
ail_block = self._convert(block_node)
|
|
643
826
|
|
|
644
827
|
if type(ail_block) is ailment.Block:
|
|
828
|
+
# remove constant pc assignments
|
|
829
|
+
ail_block.statements = [
|
|
830
|
+
stmt
|
|
831
|
+
for stmt in ail_block.statements
|
|
832
|
+
if not (
|
|
833
|
+
isinstance(stmt, ailment.Stmt.Assignment)
|
|
834
|
+
and isinstance(stmt.dst, ailment.Expr.Register)
|
|
835
|
+
and stmt.dst.reg_offset == self.project.arch.ip_offset
|
|
836
|
+
and isinstance(stmt.src, ailment.Expr.Const)
|
|
837
|
+
)
|
|
838
|
+
]
|
|
839
|
+
|
|
645
840
|
self._blocks_by_addr_and_size[(block_node.addr, block_node.size)] = ail_block
|
|
646
841
|
|
|
647
842
|
def _convert(self, block_node):
|
|
@@ -780,7 +975,7 @@ class Clinic(Analysis):
|
|
|
780
975
|
ail_graph: networkx.DiGraph,
|
|
781
976
|
remove_dead_memdefs=False,
|
|
782
977
|
stack_pointer_tracker=None,
|
|
783
|
-
cache:
|
|
978
|
+
cache: dict[ailment.Block, NamedTuple] | None = None,
|
|
784
979
|
):
|
|
785
980
|
"""
|
|
786
981
|
Simplify all blocks in self._blocks.
|
|
@@ -792,7 +987,7 @@ class Clinic(Analysis):
|
|
|
792
987
|
:return: None
|
|
793
988
|
"""
|
|
794
989
|
|
|
795
|
-
blocks_by_addr_and_idx:
|
|
990
|
+
blocks_by_addr_and_idx: dict[tuple[int, int | None], ailment.Block] = {}
|
|
796
991
|
|
|
797
992
|
for ail_block in ail_graph.nodes():
|
|
798
993
|
simplified = self._simplify_block(
|
|
@@ -860,6 +1055,7 @@ class Clinic(Analysis):
|
|
|
860
1055
|
narrow_expressions=False,
|
|
861
1056
|
only_consts=False,
|
|
862
1057
|
fold_callexprs_into_conditions=False,
|
|
1058
|
+
rewrite_ccalls=True,
|
|
863
1059
|
) -> None:
|
|
864
1060
|
"""
|
|
865
1061
|
Simplify the entire function until it reaches a fixed point.
|
|
@@ -875,6 +1071,7 @@ class Clinic(Analysis):
|
|
|
875
1071
|
narrow_expressions=narrow_expressions and idx == 0,
|
|
876
1072
|
only_consts=only_consts,
|
|
877
1073
|
fold_callexprs_into_conditions=fold_callexprs_into_conditions,
|
|
1074
|
+
rewrite_ccalls=rewrite_ccalls,
|
|
878
1075
|
)
|
|
879
1076
|
if not simplified:
|
|
880
1077
|
break
|
|
@@ -889,6 +1086,7 @@ class Clinic(Analysis):
|
|
|
889
1086
|
narrow_expressions=False,
|
|
890
1087
|
only_consts=False,
|
|
891
1088
|
fold_callexprs_into_conditions=False,
|
|
1089
|
+
rewrite_ccalls=True,
|
|
892
1090
|
):
|
|
893
1091
|
"""
|
|
894
1092
|
Simplify the entire function once.
|
|
@@ -908,6 +1106,7 @@ class Clinic(Analysis):
|
|
|
908
1106
|
only_consts=only_consts,
|
|
909
1107
|
fold_callexprs_into_conditions=fold_callexprs_into_conditions,
|
|
910
1108
|
use_callee_saved_regs_at_return=not self._register_save_areas_removed,
|
|
1109
|
+
rewrite_ccalls=rewrite_ccalls,
|
|
911
1110
|
)
|
|
912
1111
|
# cache the simplifier's RDA analysis
|
|
913
1112
|
self.reaching_definitions = simp._reaching_definitions
|
|
@@ -923,8 +1122,8 @@ class Clinic(Analysis):
|
|
|
923
1122
|
variable_kb=None,
|
|
924
1123
|
**kwargs,
|
|
925
1124
|
):
|
|
926
|
-
addr_and_idx_to_blocks:
|
|
927
|
-
addr_to_blocks:
|
|
1125
|
+
addr_and_idx_to_blocks: dict[tuple[int, int | None], ailment.Block] = {}
|
|
1126
|
+
addr_to_blocks: dict[int, set[ailment.Block]] = defaultdict(set)
|
|
928
1127
|
|
|
929
1128
|
# update blocks_map to allow node_addr to node lookup
|
|
930
1129
|
def _updatedict_handler(node):
|
|
@@ -963,10 +1162,10 @@ class Clinic(Analysis):
|
|
|
963
1162
|
return ail_graph
|
|
964
1163
|
|
|
965
1164
|
@timethis
|
|
966
|
-
def _make_argument_list(self) ->
|
|
1165
|
+
def _make_argument_list(self) -> list[SimVariable]:
|
|
967
1166
|
if self.function.calling_convention is not None and self.function.prototype is not None:
|
|
968
|
-
args:
|
|
969
|
-
arg_vars:
|
|
1167
|
+
args: list[SimFunctionArgument] = self.function.calling_convention.arg_locs(self.function.prototype)
|
|
1168
|
+
arg_vars: list[SimVariable] = []
|
|
970
1169
|
if args:
|
|
971
1170
|
arg_names = self.function.prototype.arg_names or [f"a{i}" for i in range(len(args))]
|
|
972
1171
|
for idx, arg in enumerate(args):
|
|
@@ -1041,7 +1240,9 @@ class Clinic(Analysis):
|
|
|
1041
1240
|
return simp.result_block
|
|
1042
1241
|
return None
|
|
1043
1242
|
|
|
1044
|
-
|
|
1243
|
+
# rewriting call-sites at this point, pre-inlining, causes issues with incorrect call signatures
|
|
1244
|
+
if not self._inlining_parents:
|
|
1245
|
+
AILGraphWalker(ail_graph, _handler, replace_nodes=True).walk()
|
|
1045
1246
|
|
|
1046
1247
|
return ail_graph, TempClass.stack_arg_offsets
|
|
1047
1248
|
|
|
@@ -1050,6 +1251,10 @@ class Clinic(Analysis):
|
|
|
1050
1251
|
"""
|
|
1051
1252
|
Work on each return statement and fill in its return expressions.
|
|
1052
1253
|
"""
|
|
1254
|
+
if self._inlining_parents:
|
|
1255
|
+
# for inlining, we want to keep the return statement separate from the return value, so that
|
|
1256
|
+
# the former can be removed while preserving the latter
|
|
1257
|
+
return ail_graph
|
|
1053
1258
|
|
|
1054
1259
|
if self.function.calling_convention is None:
|
|
1055
1260
|
# unknown calling convention. cannot do much about return expressions.
|
|
@@ -1060,7 +1265,7 @@ class Clinic(Analysis):
|
|
|
1060
1265
|
return ail_graph
|
|
1061
1266
|
|
|
1062
1267
|
@timethis
|
|
1063
|
-
def _make_function_prototype(self, arg_list:
|
|
1268
|
+
def _make_function_prototype(self, arg_list: list[SimVariable], variable_kb):
|
|
1064
1269
|
if self.function.prototype is not None:
|
|
1065
1270
|
if not self.function.is_prototype_guessed:
|
|
1066
1271
|
# do not overwrite an existing function prototype
|
|
@@ -1567,7 +1772,7 @@ class Clinic(Analysis):
|
|
|
1567
1772
|
|
|
1568
1773
|
@staticmethod
|
|
1569
1774
|
def _remove_redundant_jump_blocks(ail_graph):
|
|
1570
|
-
def first_conditional_jump(block: ailment.Block) ->
|
|
1775
|
+
def first_conditional_jump(block: ailment.Block) -> ailment.Stmt.ConditionalJump | None:
|
|
1571
1776
|
for stmt in block.statements:
|
|
1572
1777
|
if isinstance(stmt, ailment.Stmt.ConditionalJump):
|
|
1573
1778
|
return stmt
|
|
@@ -1633,7 +1838,7 @@ class Clinic(Analysis):
|
|
|
1633
1838
|
expr: ailment.expression.Expression,
|
|
1634
1839
|
stmt_idx: int,
|
|
1635
1840
|
stmt: ailment.statement.Statement,
|
|
1636
|
-
block:
|
|
1841
|
+
block: ailment.Block | None,
|
|
1637
1842
|
):
|
|
1638
1843
|
if expr is None:
|
|
1639
1844
|
return None
|
|
@@ -1645,7 +1850,7 @@ class Clinic(Analysis):
|
|
|
1645
1850
|
variables.add(v)
|
|
1646
1851
|
return ailment.AILBlockWalker._handle_expr(walker, expr_idx, expr, stmt_idx, stmt, block)
|
|
1647
1852
|
|
|
1648
|
-
def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block:
|
|
1853
|
+
def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block: ailment.Block | None):
|
|
1649
1854
|
if stmt.variable and stmt.variable in global_vars:
|
|
1650
1855
|
variables.add(stmt.variable)
|
|
1651
1856
|
return ailment.AILBlockWalker._handle_Store(walker, stmt_idx, stmt, block)
|
|
@@ -1656,17 +1861,17 @@ class Clinic(Analysis):
|
|
|
1656
1861
|
return variables
|
|
1657
1862
|
|
|
1658
1863
|
@staticmethod
|
|
1659
|
-
def _collect_data_refs(ail_graph) ->
|
|
1864
|
+
def _collect_data_refs(ail_graph) -> dict[int, list[DataRefDesc]]:
|
|
1660
1865
|
# pylint:disable=unused-argument
|
|
1661
1866
|
walker = ailment.AILBlockWalker()
|
|
1662
|
-
data_refs:
|
|
1867
|
+
data_refs: dict[int, list[DataRefDesc]] = defaultdict(list)
|
|
1663
1868
|
|
|
1664
1869
|
def handle_Const(
|
|
1665
1870
|
expr_idx: int,
|
|
1666
1871
|
expr: ailment.expression.Const,
|
|
1667
1872
|
stmt_idx: int,
|
|
1668
1873
|
stmt: ailment.statement.Statement,
|
|
1669
|
-
block:
|
|
1874
|
+
block: ailment.Block | None,
|
|
1670
1875
|
):
|
|
1671
1876
|
if isinstance(expr.value, int) and hasattr(expr, "ins_addr"):
|
|
1672
1877
|
data_refs[block.addr].append(
|
|
@@ -1684,7 +1889,7 @@ class Clinic(Analysis):
|
|
|
1684
1889
|
expr: ailment.expression.Load,
|
|
1685
1890
|
stmt_idx: int,
|
|
1686
1891
|
stmt: ailment.statement.Statement,
|
|
1687
|
-
block:
|
|
1892
|
+
block: ailment.Block | None,
|
|
1688
1893
|
):
|
|
1689
1894
|
if isinstance(expr.addr, ailment.expression.Const):
|
|
1690
1895
|
addr = expr.addr
|
|
@@ -1714,7 +1919,7 @@ class Clinic(Analysis):
|
|
|
1714
1919
|
|
|
1715
1920
|
return ailment.AILBlockWalker._handle_Load(walker, expr_idx, expr, stmt_idx, stmt, block)
|
|
1716
1921
|
|
|
1717
|
-
def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block:
|
|
1922
|
+
def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block: ailment.Block | None):
|
|
1718
1923
|
if isinstance(stmt.addr, ailment.expression.Const):
|
|
1719
1924
|
addr = stmt.addr
|
|
1720
1925
|
if isinstance(addr.value, int) and hasattr(addr, "ins_addr"):
|
|
@@ -1760,7 +1965,7 @@ class Clinic(Analysis):
|
|
|
1760
1965
|
op_type = kwargs.pop("op_type")
|
|
1761
1966
|
return isinstance(stmt, ailment.Stmt.Call) and op_type == OP_BEFORE
|
|
1762
1967
|
|
|
1763
|
-
def parse_variable_addr(self, addr: ailment.Expr.Expression) ->
|
|
1968
|
+
def parse_variable_addr(self, addr: ailment.Expr.Expression) -> tuple[Any, Any] | None:
|
|
1764
1969
|
if isinstance(addr, ailment.Expr.Const):
|
|
1765
1970
|
return addr, 0
|
|
1766
1971
|
if isinstance(addr, ailment.Expr.BinaryOp):
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from collections import defaultdict, OrderedDict
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Any
|
|
3
|
+
from collections.abc import Generator
|
|
3
4
|
import operator
|
|
4
5
|
import logging
|
|
5
6
|
|
|
@@ -124,6 +125,7 @@ _ail2claripy_op_mapping = {
|
|
|
124
125
|
"SCarry": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
125
126
|
"SBorrow": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
126
127
|
"ExpCmpNE": lambda expr, _, m: _dummy_bools(expr, m),
|
|
128
|
+
"CmpORD": lambda expr, _, m: _dummy_bvs(expr, m), # in case CmpORDRewriter fails
|
|
127
129
|
}
|
|
128
130
|
|
|
129
131
|
#
|
|
@@ -138,8 +140,8 @@ class ConditionProcessor:
|
|
|
138
140
|
|
|
139
141
|
def __init__(self, arch, condition_mapping=None):
|
|
140
142
|
self.arch = arch
|
|
141
|
-
self._condition_mapping:
|
|
142
|
-
self.jump_table_conds:
|
|
143
|
+
self._condition_mapping: dict[str, Any] = {} if condition_mapping is None else condition_mapping
|
|
144
|
+
self.jump_table_conds: dict[int, set] = defaultdict(set)
|
|
143
145
|
self.edge_conditions = {}
|
|
144
146
|
self.reaching_conditions = {}
|
|
145
147
|
self.guarding_conditions = {}
|
|
@@ -167,7 +169,7 @@ class ConditionProcessor:
|
|
|
167
169
|
predicate = claripy.true
|
|
168
170
|
return predicate
|
|
169
171
|
|
|
170
|
-
def recover_edge_conditions(self, region, graph=None) ->
|
|
172
|
+
def recover_edge_conditions(self, region, graph=None) -> dict:
|
|
171
173
|
edge_conditions = {}
|
|
172
174
|
# traverse the graph to recover the condition for each edge
|
|
173
175
|
graph = graph or region.graph
|
|
@@ -181,8 +183,13 @@ class ConditionProcessor:
|
|
|
181
183
|
self.edge_conditions = edge_conditions
|
|
182
184
|
|
|
183
185
|
def recover_reaching_conditions(
|
|
184
|
-
self, region, graph=None, with_successors=False, case_entry_to_switch_head:
|
|
186
|
+
self, region, graph=None, with_successors=False, case_entry_to_switch_head: dict[int, int] | None = None
|
|
185
187
|
):
|
|
188
|
+
"""
|
|
189
|
+
Recover the reaching conditions for each block in an acyclic graph. Note that we assume the graph that's passed
|
|
190
|
+
in is acyclic.
|
|
191
|
+
"""
|
|
192
|
+
|
|
186
193
|
def _strictly_postdominates(inv_idoms, node_a, node_b):
|
|
187
194
|
"""
|
|
188
195
|
Does node A strictly post-dominate node B on the graph?
|
|
@@ -457,7 +464,7 @@ class ConditionProcessor:
|
|
|
457
464
|
raise NotImplementedError()
|
|
458
465
|
|
|
459
466
|
@classmethod
|
|
460
|
-
def get_last_statements(cls, block) ->
|
|
467
|
+
def get_last_statements(cls, block) -> list[ailment.Stmt.Statement | None]:
|
|
461
468
|
if type(block) is SequenceNode:
|
|
462
469
|
for last_node in reversed(block.nodes):
|
|
463
470
|
try:
|
|
@@ -837,7 +844,7 @@ class ConditionProcessor:
|
|
|
837
844
|
return symbol
|
|
838
845
|
|
|
839
846
|
@staticmethod
|
|
840
|
-
def sympy_expr_to_claripy_ast(expr, memo:
|
|
847
|
+
def sympy_expr_to_claripy_ast(expr, memo: dict):
|
|
841
848
|
if expr.is_Symbol:
|
|
842
849
|
return memo[expr]
|
|
843
850
|
if isinstance(expr, sympy.Or):
|
|
@@ -1134,7 +1141,7 @@ class ConditionProcessor:
|
|
|
1134
1141
|
|
|
1135
1142
|
@staticmethod
|
|
1136
1143
|
def _remove_crossing_edges_between_cases(
|
|
1137
|
-
graph: networkx.DiGraph, case_entry_to_switch_head:
|
|
1144
|
+
graph: networkx.DiGraph, case_entry_to_switch_head: dict[int, int]
|
|
1138
1145
|
) -> networkx.DiGraph:
|
|
1139
1146
|
starting_nodes = {node for node in graph if node.addr in case_entry_to_switch_head}
|
|
1140
1147
|
if not starting_nodes:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Any, TYPE_CHECKING
|
|
2
2
|
|
|
3
3
|
from .clinic import Clinic
|
|
4
4
|
from .structured_codegen import BaseStructuredCodeGenerator
|
|
@@ -25,13 +25,13 @@ class DecompilationCache:
|
|
|
25
25
|
|
|
26
26
|
def __init__(self, addr):
|
|
27
27
|
self.addr = addr
|
|
28
|
-
self.type_constraints:
|
|
28
|
+
self.type_constraints: set | None = None
|
|
29
29
|
self.func_typevar = None
|
|
30
|
-
self.var_to_typevar:
|
|
31
|
-
self.codegen:
|
|
32
|
-
self.clinic:
|
|
33
|
-
self.ite_exprs:
|
|
34
|
-
self.binop_operators:
|
|
30
|
+
self.var_to_typevar: dict | None = None
|
|
31
|
+
self.codegen: BaseStructuredCodeGenerator | None = None
|
|
32
|
+
self.clinic: Clinic | None = None
|
|
33
|
+
self.ite_exprs: set[tuple[int, Any]] | None = None
|
|
34
|
+
self.binop_operators: dict["OpDescriptor", str] | None = None
|
|
35
35
|
|
|
36
36
|
@property
|
|
37
37
|
def local_types(self):
|