angr 9.2.135__py3-none-manylinux2014_x86_64.whl → 9.2.136__py3-none-manylinux2014_x86_64.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 +3 -7
- angr/analyses/analysis.py +4 -0
- angr/analyses/backward_slice.py +1 -2
- angr/analyses/binary_optimizer.py +3 -4
- angr/analyses/bindiff.py +4 -6
- angr/analyses/boyscout.py +1 -3
- angr/analyses/callee_cleanup_finder.py +4 -4
- angr/analyses/calling_convention/calling_convention.py +4 -3
- angr/analyses/calling_convention/fact_collector.py +0 -1
- angr/analyses/cdg.py +1 -2
- angr/analyses/cfg/cfb.py +1 -3
- angr/analyses/cfg/cfg.py +2 -2
- angr/analyses/cfg/cfg_base.py +37 -35
- angr/analyses/cfg/cfg_emulated.py +1 -1
- angr/analyses/cfg/cfg_fast.py +62 -15
- angr/analyses/cfg/cfg_fast_soot.py +1 -1
- angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
- angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +46 -10
- angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +5 -1
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +50 -14
- angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
- angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +24 -5
- angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +2 -5
- angr/analyses/congruency_check.py +2 -3
- angr/analyses/data_dep/data_dependency_analysis.py +2 -2
- angr/analyses/ddg.py +1 -4
- angr/analyses/decompiler/ail_simplifier.py +3 -4
- angr/analyses/decompiler/clinic.py +42 -7
- angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
- angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +2 -2
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +1 -1
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +1 -1
- angr/analyses/decompiler/structuring/phoenix.py +1 -1
- angr/analyses/disassembly.py +5 -5
- angr/analyses/fcp/__init__.py +4 -0
- angr/analyses/fcp/fcp.py +429 -0
- angr/analyses/identifier/identify.py +1 -3
- angr/analyses/loopfinder.py +4 -3
- angr/analyses/patchfinder.py +1 -1
- angr/analyses/propagator/engine_base.py +4 -3
- angr/analyses/propagator/propagator.py +14 -53
- angr/analyses/reassembler.py +1 -2
- angr/analyses/s_propagator.py +1 -3
- angr/analyses/soot_class_hierarchy.py +1 -2
- angr/analyses/stack_pointer_tracker.py +18 -2
- angr/analyses/static_hooker.py +1 -2
- angr/analyses/typehoon/simple_solver.py +2 -2
- angr/analyses/variable_recovery/variable_recovery_fast.py +1 -2
- angr/analyses/veritesting.py +4 -7
- angr/analyses/vfg.py +1 -1
- angr/analyses/vsa_ddg.py +1 -2
- angr/block.py +3 -2
- angr/callable.py +1 -3
- angr/calling_conventions.py +3 -3
- angr/codenode.py +5 -1
- angr/concretization_strategies/__init__.py +1 -83
- angr/concretization_strategies/any.py +2 -1
- angr/concretization_strategies/any_named.py +1 -1
- angr/concretization_strategies/base.py +81 -0
- angr/concretization_strategies/controlled_data.py +2 -1
- angr/concretization_strategies/eval.py +2 -1
- angr/concretization_strategies/logging.py +3 -1
- angr/concretization_strategies/max.py +2 -1
- angr/concretization_strategies/nonzero.py +2 -1
- angr/concretization_strategies/nonzero_range.py +2 -1
- angr/concretization_strategies/norepeats.py +2 -1
- angr/concretization_strategies/norepeats_range.py +2 -1
- angr/concretization_strategies/range.py +2 -1
- angr/concretization_strategies/signed_add.py +2 -1
- angr/concretization_strategies/single.py +2 -1
- angr/concretization_strategies/solutions.py +2 -1
- angr/concretization_strategies/unlimited_range.py +2 -1
- angr/engines/__init__.py +8 -5
- angr/engines/engine.py +3 -5
- angr/engines/failure.py +4 -5
- angr/engines/procedure.py +5 -7
- angr/engines/soot/expressions/__init__.py +22 -23
- angr/engines/soot/expressions/base.py +4 -4
- angr/engines/soot/expressions/invoke.py +1 -2
- angr/engines/soot/statements/__init__.py +9 -10
- angr/engines/soot/values/__init__.py +9 -10
- angr/engines/soot/values/arrayref.py +3 -3
- angr/engines/soot/values/instancefieldref.py +3 -2
- angr/engines/successors.py +7 -6
- angr/engines/syscall.py +4 -6
- angr/engines/unicorn.py +3 -2
- angr/engines/vex/claripy/ccall.py +8 -10
- angr/engines/vex/claripy/datalayer.py +4 -5
- angr/exploration_techniques/__init__.py +0 -2
- angr/exploration_techniques/spiller.py +1 -3
- angr/exploration_techniques/stochastic.py +2 -3
- angr/factory.py +3 -9
- angr/knowledge_plugins/cfg/cfg_model.py +20 -17
- angr/knowledge_plugins/functions/function.py +70 -73
- angr/knowledge_plugins/functions/function_manager.py +8 -7
- angr/knowledge_plugins/functions/function_parser.py +1 -1
- angr/knowledge_plugins/functions/soot_function.py +16 -16
- angr/knowledge_plugins/propagations/propagation_model.py +4 -5
- angr/knowledge_plugins/propagations/states.py +0 -511
- angr/procedures/libc/memcpy.py +4 -4
- angr/procedures/procedure_dict.py +3 -2
- angr/protos/__init__.py +2 -5
- angr/protos/cfg_pb2.py +21 -18
- angr/protos/function_pb2.py +17 -14
- angr/protos/primitives_pb2.py +44 -39
- angr/protos/variables_pb2.py +36 -31
- angr/protos/xrefs_pb2.py +15 -12
- angr/sim_procedure.py +15 -16
- angr/sim_variable.py +13 -1
- angr/simos/__init__.py +2 -0
- angr/simos/javavm.py +4 -6
- angr/simos/xbox.py +32 -0
- angr/state_plugins/__init__.py +0 -2
- angr/state_plugins/callstack.py +4 -4
- angr/state_plugins/cgc.py +3 -2
- angr/state_plugins/gdb.py +6 -5
- angr/state_plugins/globals.py +1 -2
- angr/state_plugins/heap/heap_brk.py +1 -2
- angr/state_plugins/history.py +10 -12
- angr/state_plugins/inspect.py +3 -5
- angr/state_plugins/libc.py +2 -2
- angr/state_plugins/log.py +8 -10
- angr/state_plugins/loop_data.py +1 -2
- angr/state_plugins/posix.py +7 -7
- angr/state_plugins/preconstrainer.py +2 -3
- angr/state_plugins/scratch.py +5 -8
- angr/state_plugins/sim_action.py +3 -3
- angr/state_plugins/solver.py +8 -3
- angr/state_plugins/symbolizer.py +5 -4
- angr/state_plugins/uc_manager.py +3 -3
- angr/state_plugins/unicorn_engine.py +5 -1
- angr/state_plugins/view.py +3 -5
- angr/storage/file.py +3 -5
- angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
- angr/storage/memory_mixins/bvv_conversion_mixin.py +3 -3
- angr/storage/memory_mixins/clouseau_mixin.py +1 -3
- angr/storage/memory_mixins/name_resolution_mixin.py +1 -3
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +13 -15
- angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -22
- angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
- angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
- angr/storage/memory_mixins/paged_memory/privileged_mixin.py +3 -4
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
- angr/storage/memory_mixins/smart_find_mixin.py +1 -1
- angr/storage/memory_mixins/underconstrained_mixin.py +1 -1
- angr/storage/memory_mixins/unwrapper_mixin.py +1 -3
- angr/utils/enums_conv.py +28 -12
- angr/utils/segment_list.py +25 -22
- angr/utils/timing.py +18 -1
- angr/vaults.py +5 -6
- {angr-9.2.135.dist-info → angr-9.2.136.dist-info}/METADATA +6 -6
- {angr-9.2.135.dist-info → angr-9.2.136.dist-info}/RECORD +160 -159
- {angr-9.2.135.dist-info → angr-9.2.136.dist-info}/WHEEL +1 -1
- angr/analyses/propagator/outdated_definition_walker.py +0 -159
- angr/analyses/propagator/tmpvar_finder.py +0 -18
- angr/engines/concrete.py +0 -180
- angr/exploration_techniques/symbion.py +0 -80
- angr/state_plugins/concrete.py +0 -295
- {angr-9.2.135.dist-info → angr-9.2.136.dist-info}/LICENSE +0 -0
- {angr-9.2.135.dist-info → angr-9.2.136.dist-info}/entry_points.txt +0 -0
- {angr-9.2.135.dist-info → angr-9.2.136.dist-info}/top_level.txt +0 -0
|
@@ -75,7 +75,31 @@ class ConstantResolver(IndirectJumpResolver):
|
|
|
75
75
|
|
|
76
76
|
vex_block = block.vex
|
|
77
77
|
if isinstance(vex_block.next, pyvex.expr.RdTmp):
|
|
78
|
-
|
|
78
|
+
tmp_stmt_idx, tmp_ins_addr = self._find_tmp_write_stmt_and_ins(vex_block, vex_block.next.tmp)
|
|
79
|
+
if tmp_stmt_idx is None or tmp_ins_addr is None:
|
|
80
|
+
return False, []
|
|
81
|
+
|
|
82
|
+
# first check: is it jumping to a target loaded from memory? if so, it should have been resolved by
|
|
83
|
+
# MemoryLoadResolver.
|
|
84
|
+
stmt = vex_block.statements[tmp_stmt_idx]
|
|
85
|
+
assert isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
86
|
+
if (
|
|
87
|
+
isinstance(stmt.data, pyvex.IRExpr.Load)
|
|
88
|
+
and isinstance(stmt.data.addr, pyvex.IRExpr.Const)
|
|
89
|
+
and stmt.data.result_size(vex_block.tyenv) == self.project.arch.bits
|
|
90
|
+
):
|
|
91
|
+
# well, if MemoryLoadResolver hasn't resolved it, we can try to resolve it here, or bail early because
|
|
92
|
+
# ConstantResolver won't help.
|
|
93
|
+
load_addr = stmt.data.addr.con.value
|
|
94
|
+
try:
|
|
95
|
+
value = self.project.loader.memory.unpack_word(load_addr, size=self.project.arch.bytes)
|
|
96
|
+
if isinstance(value, int) and self._is_target_valid(cfg, value):
|
|
97
|
+
return True, [value]
|
|
98
|
+
except KeyError:
|
|
99
|
+
pass
|
|
100
|
+
return False, []
|
|
101
|
+
|
|
102
|
+
# second check: what does the jump rely on? slice it back and see
|
|
79
103
|
b = Blade(
|
|
80
104
|
cfg.graph,
|
|
81
105
|
addr,
|
|
@@ -104,26 +128,25 @@ class ConstantResolver(IndirectJumpResolver):
|
|
|
104
128
|
block = self.project.factory.block(pred_addr, cross_insn_opt=True).vex
|
|
105
129
|
if stmt_idx != DEFAULT_STATEMENT:
|
|
106
130
|
stmt = block.statements[stmt_idx]
|
|
107
|
-
if
|
|
131
|
+
if (
|
|
132
|
+
isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
133
|
+
and isinstance(stmt.data, pyvex.IRExpr.Load)
|
|
134
|
+
and not isinstance(stmt.data.addr, pyvex.IRExpr.Const)
|
|
135
|
+
):
|
|
108
136
|
# loading from memory - unsupported
|
|
109
137
|
return False, []
|
|
110
138
|
break
|
|
111
139
|
|
|
112
140
|
_l.debug("ConstantResolver: Propagating for %r at %#x.", func, addr)
|
|
113
|
-
prop = self.project.analyses.
|
|
114
|
-
func
|
|
115
|
-
only_consts=True,
|
|
116
|
-
do_binops=True,
|
|
141
|
+
prop = self.project.analyses.FastConstantPropagation(
|
|
142
|
+
func,
|
|
117
143
|
vex_cross_insn_opt=False,
|
|
118
|
-
completed_funcs=cfg._completed_functions,
|
|
119
144
|
load_callback=PropagatorLoadCallback(self.project).propagator_load_callback,
|
|
120
|
-
cache_results=True,
|
|
121
|
-
key_prefix="cfg_intermediate",
|
|
122
145
|
)
|
|
123
146
|
|
|
124
147
|
replacements = prop.replacements
|
|
125
148
|
if replacements:
|
|
126
|
-
block_loc = CodeLocation(block.addr,
|
|
149
|
+
block_loc = CodeLocation(block.addr, tmp_stmt_idx, ins_addr=tmp_ins_addr)
|
|
127
150
|
tmp_var = vex_vars.VEXTmp(vex_block.next.tmp)
|
|
128
151
|
|
|
129
152
|
if exists_in_replacements(replacements, block_loc, tmp_var):
|
|
@@ -135,5 +158,18 @@ class ConstantResolver(IndirectJumpResolver):
|
|
|
135
158
|
and self._is_target_valid(cfg, resolved_tmp.args[0])
|
|
136
159
|
):
|
|
137
160
|
return True, [resolved_tmp.args[0]]
|
|
161
|
+
if isinstance(resolved_tmp, int) and self._is_target_valid(cfg, resolved_tmp):
|
|
162
|
+
return True, [resolved_tmp]
|
|
138
163
|
|
|
139
164
|
return False, []
|
|
165
|
+
|
|
166
|
+
@staticmethod
|
|
167
|
+
def _find_tmp_write_stmt_and_ins(vex_block, tmp: int) -> tuple[int | None, int | None]:
|
|
168
|
+
stmt_idx = None
|
|
169
|
+
for idx, stmt in enumerate(reversed(vex_block.statements)):
|
|
170
|
+
if isinstance(stmt, pyvex.IRStmt.IMark) and stmt_idx is not None:
|
|
171
|
+
ins_addr = stmt.addr + stmt.delta
|
|
172
|
+
return stmt_idx, ins_addr
|
|
173
|
+
if isinstance(stmt, pyvex.IRStmt.WrTmp) and stmt.tmp == tmp:
|
|
174
|
+
stmt_idx = len(vex_block.statements) - idx - 1
|
|
175
|
+
return None, None
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import cle
|
|
3
|
+
from angr.analyses.cfg.indirect_jump_resolvers import MemoryLoadResolver
|
|
3
4
|
|
|
4
5
|
from . import MipsElfFastResolver
|
|
5
6
|
from . import X86ElfPicPltResolver
|
|
@@ -19,6 +20,9 @@ DEFAULT_RESOLVERS = {
|
|
|
19
20
|
cle.PE: [
|
|
20
21
|
X86PeIatResolver,
|
|
21
22
|
],
|
|
23
|
+
cle.XBE: [
|
|
24
|
+
X86PeIatResolver,
|
|
25
|
+
],
|
|
22
26
|
},
|
|
23
27
|
"AMD64": {
|
|
24
28
|
cle.MetaELF: [
|
|
@@ -54,7 +58,7 @@ DEFAULT_RESOLVERS = {
|
|
|
54
58
|
ArmElfFastResolver,
|
|
55
59
|
]
|
|
56
60
|
},
|
|
57
|
-
"ALL": [JumpTableResolver, ConstantResolver],
|
|
61
|
+
"ALL": [MemoryLoadResolver, JumpTableResolver, ConstantResolver],
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
|
|
@@ -10,6 +10,7 @@ import functools
|
|
|
10
10
|
import pyvex
|
|
11
11
|
import claripy
|
|
12
12
|
from archinfo.arch_arm import is_arm_arch
|
|
13
|
+
from claripy.annotation import UninitializedAnnotation
|
|
13
14
|
|
|
14
15
|
from angr import sim_options as o
|
|
15
16
|
from angr import BP, BP_BEFORE, BP_AFTER
|
|
@@ -144,20 +145,22 @@ class ConstantValueManager:
|
|
|
144
145
|
|
|
145
146
|
__slots__ = (
|
|
146
147
|
"func",
|
|
148
|
+
"indirect_jump_addr",
|
|
147
149
|
"kb",
|
|
148
150
|
"mapping",
|
|
149
151
|
"project",
|
|
150
152
|
)
|
|
151
153
|
|
|
152
|
-
def __init__(self, project: Project, kb, func: Function):
|
|
154
|
+
def __init__(self, project: Project, kb, func: Function, ij_addr: int):
|
|
153
155
|
self.project = project
|
|
154
156
|
self.kb = kb
|
|
155
157
|
self.func = func
|
|
158
|
+
self.indirect_jump_addr = ij_addr
|
|
156
159
|
|
|
157
160
|
self.mapping: dict[Any, dict[Any, claripy.ast.Base]] | None = None
|
|
158
161
|
|
|
159
162
|
def reg_read_callback(self, state: SimState):
|
|
160
|
-
if
|
|
163
|
+
if self.mapping is None:
|
|
161
164
|
self._build_mapping()
|
|
162
165
|
assert self.mapping is not None
|
|
163
166
|
|
|
@@ -168,18 +171,54 @@ class ConstantValueManager:
|
|
|
168
171
|
reg_read_offset = reg_read_offset.args[0]
|
|
169
172
|
variable = VEXReg(reg_read_offset, state.inspect.reg_read_length)
|
|
170
173
|
if variable in self.mapping[codeloc]:
|
|
171
|
-
|
|
174
|
+
v = self.mapping[codeloc][variable]
|
|
175
|
+
if isinstance(v, int):
|
|
176
|
+
v = claripy.BVV(v, state.inspect.reg_read_length * state.arch.byte_width)
|
|
177
|
+
state.inspect.reg_read_expr = v
|
|
172
178
|
|
|
173
179
|
def _build_mapping(self):
|
|
174
180
|
# constant propagation
|
|
175
|
-
l.debug("JumpTable: Propagating for %r.", self.func)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
181
|
+
l.debug("JumpTable: Propagating for %r at %#x.", self.func, self.indirect_jump_addr)
|
|
182
|
+
|
|
183
|
+
# determine blocks to run FCP on
|
|
184
|
+
|
|
185
|
+
# - include at most three levels of successors from the entrypoint
|
|
186
|
+
startpoint = self.func.startpoint
|
|
187
|
+
blocks = set()
|
|
188
|
+
succs = [startpoint]
|
|
189
|
+
for _ in range(3):
|
|
190
|
+
new_succs = []
|
|
191
|
+
for node in succs:
|
|
192
|
+
if node in blocks:
|
|
193
|
+
continue
|
|
194
|
+
blocks.add(node)
|
|
195
|
+
if node.addr == self.indirect_jump_addr:
|
|
196
|
+
# stop at the indirect jump block
|
|
197
|
+
continue
|
|
198
|
+
new_succs += list(self.func.graph.successors(node))
|
|
199
|
+
succs = new_succs
|
|
200
|
+
if not succs:
|
|
201
|
+
break
|
|
202
|
+
|
|
203
|
+
# - include at most six levels of predecessors from the indirect jump block
|
|
204
|
+
ij_block = self.func.get_node(self.indirect_jump_addr)
|
|
205
|
+
preds = [ij_block]
|
|
206
|
+
for _ in range(6):
|
|
207
|
+
new_preds = []
|
|
208
|
+
for node in preds:
|
|
209
|
+
if node in blocks:
|
|
210
|
+
continue
|
|
211
|
+
blocks.add(node)
|
|
212
|
+
new_preds += list(self.func.graph.predecessors(node))
|
|
213
|
+
preds = new_preds
|
|
214
|
+
if not preds:
|
|
215
|
+
break
|
|
216
|
+
|
|
217
|
+
prop = self.project.analyses.FastConstantPropagation(
|
|
218
|
+
self.func,
|
|
219
|
+
blocks=blocks,
|
|
179
220
|
vex_cross_insn_opt=True,
|
|
180
221
|
load_callback=PropagatorLoadCallback(self.project).propagator_load_callback,
|
|
181
|
-
cache_results=True,
|
|
182
|
-
key_prefix="cfg_intermediate",
|
|
183
222
|
)
|
|
184
223
|
self.mapping = prop.replacements
|
|
185
224
|
|
|
@@ -853,7 +892,7 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
853
892
|
potential_call_table = jumpkind == "Ijk_Call" or self._sp_moved_up(block) or len(func.block_addrs_set) <= 5
|
|
854
893
|
# we only perform full-function propagation for jump tables or call tables in really small functions
|
|
855
894
|
if not potential_call_table or len(func.block_addrs_set) <= 5:
|
|
856
|
-
cv_manager = ConstantValueManager(self.project, cfg.kb, func)
|
|
895
|
+
cv_manager = ConstantValueManager(self.project, cfg.kb, func, addr)
|
|
857
896
|
else:
|
|
858
897
|
cv_manager = None
|
|
859
898
|
|
|
@@ -2131,7 +2170,7 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
2131
2170
|
read_addr = state.inspect.mem_read_address
|
|
2132
2171
|
cond = state.inspect.mem_read_condition
|
|
2133
2172
|
|
|
2134
|
-
if not isinstance(read_addr, int) and read_addr.
|
|
2173
|
+
if not isinstance(read_addr, int) and read_addr.has_annotation_type(UninitializedAnnotation) and cond is None:
|
|
2135
2174
|
# if this AST has been initialized before, just use the cached addr
|
|
2136
2175
|
cached_addr = self._cached_memread_addrs.get(read_addr, None)
|
|
2137
2176
|
if cached_addr is not None:
|
|
@@ -2402,6 +2441,3 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
2402
2441
|
if load_stmt_ids:
|
|
2403
2442
|
return [load_stmt_ids[-1]]
|
|
2404
2443
|
return []
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
from angr.analyses.propagator import PropagatorAnalysis
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
import pyvex
|
|
5
|
+
|
|
6
|
+
from .resolver import IndirectJumpResolver
|
|
7
|
+
|
|
8
|
+
_l = logging.getLogger(name=__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MemoryLoadResolver(IndirectJumpResolver):
|
|
12
|
+
"""
|
|
13
|
+
Resolve an indirect jump that looks like the following::
|
|
14
|
+
|
|
15
|
+
.text:
|
|
16
|
+
call off_3314A8
|
|
17
|
+
|
|
18
|
+
.data:
|
|
19
|
+
off_3314A8 dd offset sub_1E426F
|
|
20
|
+
|
|
21
|
+
This indirect jump resolver may not be the best solution for all cases (e.g., when the .data section can be
|
|
22
|
+
intentionally altered by the binary itself).
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, project):
|
|
26
|
+
super().__init__(project, timeless=True)
|
|
27
|
+
|
|
28
|
+
def filter(self, cfg, addr, func_addr, block, jumpkind):
|
|
29
|
+
return jumpkind in {"Ijk_Boring", "Ijk_Call"}
|
|
30
|
+
|
|
31
|
+
def resolve( # pylint:disable=unused-argument
|
|
32
|
+
self,
|
|
33
|
+
cfg,
|
|
34
|
+
addr: int,
|
|
35
|
+
func_addr: int,
|
|
36
|
+
block: pyvex.IRSB,
|
|
37
|
+
jumpkind: str,
|
|
38
|
+
func_graph_complete: bool = True,
|
|
39
|
+
**kwargs,
|
|
40
|
+
):
|
|
41
|
+
"""
|
|
42
|
+
:param cfg: CFG with specified function
|
|
43
|
+
:param addr: Address of indirect jump
|
|
44
|
+
:param func_addr: Address of function of indirect jump
|
|
45
|
+
:param block: Block of indirect jump (Block object)
|
|
46
|
+
:param jumpkind: VEX jumpkind (Ijk_Boring or Ijk_Call)
|
|
47
|
+
:return: Bool tuple with replacement address
|
|
48
|
+
"""
|
|
49
|
+
vex_block = block
|
|
50
|
+
if isinstance(vex_block.next, pyvex.expr.RdTmp):
|
|
51
|
+
tmp_stmt_idx, tmp_ins_addr = self._find_tmp_write_stmt_and_ins(vex_block, vex_block.next.tmp)
|
|
52
|
+
if tmp_stmt_idx is None or tmp_ins_addr is None:
|
|
53
|
+
return False, []
|
|
54
|
+
|
|
55
|
+
stmt = vex_block.statements[tmp_stmt_idx]
|
|
56
|
+
assert isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
57
|
+
if (
|
|
58
|
+
isinstance(stmt.data, pyvex.IRExpr.Load)
|
|
59
|
+
and isinstance(stmt.data.addr, pyvex.IRExpr.Const)
|
|
60
|
+
and stmt.data.result_size(vex_block.tyenv) == self.project.arch.bits
|
|
61
|
+
):
|
|
62
|
+
load_addr = stmt.data.addr.con.value
|
|
63
|
+
try:
|
|
64
|
+
value = self.project.loader.memory.unpack_word(load_addr, size=self.project.arch.bytes)
|
|
65
|
+
if isinstance(value, int) and self._is_target_valid(cfg, value):
|
|
66
|
+
return True, [value]
|
|
67
|
+
except KeyError:
|
|
68
|
+
return False, []
|
|
69
|
+
|
|
70
|
+
return False, []
|
|
71
|
+
|
|
72
|
+
@staticmethod
|
|
73
|
+
def _find_tmp_write_stmt_and_ins(vex_block, tmp: int) -> tuple[int | None, int | None]:
|
|
74
|
+
stmt_idx = None
|
|
75
|
+
for idx, stmt in enumerate(reversed(vex_block.statements)):
|
|
76
|
+
if isinstance(stmt, pyvex.IRStmt.IMark) and stmt_idx is not None:
|
|
77
|
+
ins_addr = stmt.addr + stmt.delta
|
|
78
|
+
return stmt_idx, ins_addr
|
|
79
|
+
if isinstance(stmt, pyvex.IRStmt.WrTmp) and stmt.tmp == tmp:
|
|
80
|
+
stmt_idx = len(vex_block.statements) - idx - 1
|
|
81
|
+
return None, None
|
|
@@ -10,7 +10,7 @@ class PropagatorLoadCallback:
|
|
|
10
10
|
def __init__(self, project):
|
|
11
11
|
self.project = project
|
|
12
12
|
|
|
13
|
-
def propagator_load_callback(self, addr, size) -> bool: # pylint:disable=unused-argument
|
|
13
|
+
def propagator_load_callback(self, addr: claripy.ast.BV | int, size: int) -> bool: # pylint:disable=unused-argument
|
|
14
14
|
# only allow loading if the address falls into a read-only region
|
|
15
15
|
if isinstance(addr, claripy.ast.BV) and addr.op == "BVV":
|
|
16
16
|
addr_v = addr.args[0]
|
|
@@ -19,9 +19,28 @@ class PropagatorLoadCallback:
|
|
|
19
19
|
else:
|
|
20
20
|
return False
|
|
21
21
|
section = self.project.loader.find_section_containing(addr_v)
|
|
22
|
+
segment = None
|
|
22
23
|
if section is not None:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
if section.is_readable and not section.is_writable:
|
|
25
|
+
# read-only section
|
|
26
|
+
return True
|
|
27
|
+
else:
|
|
28
|
+
segment = self.project.loader.find_segment_containing(addr_v)
|
|
29
|
+
if segment is not None and segment.is_readable and not segment.is_writable:
|
|
30
|
+
# read-only segment
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
if (size == self.project.arch.bytes and (section is not None and section.is_readable)) or (
|
|
34
|
+
segment is not None and segment.is_readable
|
|
35
|
+
):
|
|
36
|
+
# memory is mapped and readable. does it contain a valid address?
|
|
37
|
+
try:
|
|
38
|
+
target_addr = self.project.loader.memory.unpack_word(
|
|
39
|
+
addr_v, size=size, endness=self.project.arch.memory_endness
|
|
40
|
+
)
|
|
41
|
+
if target_addr >= 0x1000 and self.project.loader.find_object_containing(target_addr) is not None:
|
|
42
|
+
return True
|
|
43
|
+
except KeyError:
|
|
44
|
+
return False
|
|
45
|
+
|
|
27
46
|
return False
|
|
@@ -3,7 +3,6 @@ import logging
|
|
|
3
3
|
|
|
4
4
|
from capstone.x86_const import X86_OP_MEM
|
|
5
5
|
|
|
6
|
-
from angr.simos import SimWindows
|
|
7
6
|
from .resolver import IndirectJumpResolver
|
|
8
7
|
|
|
9
8
|
l = logging.getLogger(name=__name__)
|
|
@@ -11,16 +10,14 @@ l = logging.getLogger(name=__name__)
|
|
|
11
10
|
|
|
12
11
|
class X86PeIatResolver(IndirectJumpResolver):
|
|
13
12
|
"""
|
|
14
|
-
A timeless indirect jump resolver for IAT in x86 PEs.
|
|
13
|
+
A timeless indirect jump resolver for IAT in x86 PEs and xbes.
|
|
15
14
|
"""
|
|
16
15
|
|
|
17
16
|
def __init__(self, project):
|
|
18
17
|
super().__init__(project, timeless=True)
|
|
19
18
|
|
|
20
19
|
def filter(self, cfg, addr, func_addr, block, jumpkind):
|
|
21
|
-
if not
|
|
22
|
-
return False
|
|
23
|
-
if jumpkind != "Ijk_Call":
|
|
20
|
+
if jumpkind not in {"Ijk_Call", "Ijk_Boring"}: # both call and jmp
|
|
24
21
|
return False
|
|
25
22
|
|
|
26
23
|
insns = self.project.factory.block(addr).capstone.insns
|
|
@@ -3,6 +3,8 @@ import logging
|
|
|
3
3
|
|
|
4
4
|
import claripy
|
|
5
5
|
|
|
6
|
+
from angr.errors import AngrIncongruencyError
|
|
7
|
+
from angr.analyses import AnalysesHub
|
|
6
8
|
from . import Analysis
|
|
7
9
|
|
|
8
10
|
l = logging.getLogger(name=__name__)
|
|
@@ -372,7 +374,4 @@ class CongruencyCheck(Analysis):
|
|
|
372
374
|
return True
|
|
373
375
|
|
|
374
376
|
|
|
375
|
-
from angr.errors import AngrIncongruencyError
|
|
376
|
-
from angr.analyses import AnalysesHub
|
|
377
|
-
|
|
378
377
|
AnalysesHub.register_default("CongruencyCheck", CongruencyCheck)
|
|
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING
|
|
|
9
9
|
from networkx import DiGraph
|
|
10
10
|
|
|
11
11
|
import claripy
|
|
12
|
-
from claripy.ast
|
|
12
|
+
from claripy.ast import BV
|
|
13
13
|
from .dep_nodes import DepNodeTypes, ConstantDepNode, MemDepNode, VarDepNode, RegDepNode, TmpDepNode
|
|
14
14
|
from .sim_act_location import SimActLocation, DEFAULT_LOCATION, ParsedInstruction
|
|
15
15
|
from angr.analyses import Analysis
|
|
@@ -173,7 +173,7 @@ class DataDependencyGraphAnalysis(Analysis):
|
|
|
173
173
|
self,
|
|
174
174
|
type_: int,
|
|
175
175
|
sim_act: SimActionData,
|
|
176
|
-
val: tuple[BV, int],
|
|
176
|
+
val: tuple[claripy.ast.BV, int],
|
|
177
177
|
*constructor_params,
|
|
178
178
|
) -> BaseDepNode:
|
|
179
179
|
"""
|
angr/analyses/ddg.py
CHANGED
|
@@ -6,8 +6,7 @@ import claripy
|
|
|
6
6
|
import networkx
|
|
7
7
|
import pyvex
|
|
8
8
|
|
|
9
|
-
from . import Analysis
|
|
10
|
-
|
|
9
|
+
from angr.analyses import Analysis, AnalysesHub
|
|
11
10
|
from angr.code_location import CodeLocation
|
|
12
11
|
from angr.errors import SimSolverModeError, SimUnsatError, AngrDDGError
|
|
13
12
|
from angr.sim_variable import (
|
|
@@ -1668,6 +1667,4 @@ class DDG(Analysis):
|
|
|
1668
1667
|
return sources
|
|
1669
1668
|
|
|
1670
1669
|
|
|
1671
|
-
from angr.analyses import AnalysesHub
|
|
1672
|
-
|
|
1673
1670
|
AnalysesHub.register_default("DDG", DDG)
|
|
@@ -216,7 +216,7 @@ class AILSimplifier(Analysis):
|
|
|
216
216
|
self._reaching_definitions = rd
|
|
217
217
|
return rd
|
|
218
218
|
|
|
219
|
-
def _compute_propagation(self
|
|
219
|
+
def _compute_propagation(self) -> SPropagatorAnalysis:
|
|
220
220
|
# Propagate expressions or return the existing result
|
|
221
221
|
if self._propagator is not None:
|
|
222
222
|
return self._propagator
|
|
@@ -225,7 +225,6 @@ class AILSimplifier(Analysis):
|
|
|
225
225
|
func_graph=self.func_graph,
|
|
226
226
|
# gp=self._gp,
|
|
227
227
|
only_consts=self._only_consts,
|
|
228
|
-
immediate_stmt_removal=immediate_stmt_removal,
|
|
229
228
|
)
|
|
230
229
|
self._propagator = prop
|
|
231
230
|
return prop
|
|
@@ -354,7 +353,7 @@ class AILSimplifier(Analysis):
|
|
|
354
353
|
):
|
|
355
354
|
repeat = False
|
|
356
355
|
narrowable_phivarids = set()
|
|
357
|
-
for def_vvarid
|
|
356
|
+
for def_vvarid in narrowing_candidates:
|
|
358
357
|
if def_vvarid in blacklist_varids:
|
|
359
358
|
continue
|
|
360
359
|
if def_vvarid in rd.phi_vvar_ids:
|
|
@@ -591,7 +590,7 @@ class AILSimplifier(Analysis):
|
|
|
591
590
|
"""
|
|
592
591
|
|
|
593
592
|
# propagator
|
|
594
|
-
propagator = self._compute_propagation(
|
|
593
|
+
propagator = self._compute_propagation()
|
|
595
594
|
replacements = propagator.replacements
|
|
596
595
|
|
|
597
596
|
# take replacements and rebuild the corresponding blocks
|
|
@@ -527,6 +527,9 @@ class Clinic(Analysis):
|
|
|
527
527
|
# TODO: Totally remove this dict
|
|
528
528
|
self._blocks_by_addr_and_size = None
|
|
529
529
|
|
|
530
|
+
# Rust-specific; only call this on Rust binaries when we can identify language and compiler
|
|
531
|
+
ail_graph = self._rewrite_rust_probestack_call(ail_graph)
|
|
532
|
+
|
|
530
533
|
# Make call-sites
|
|
531
534
|
self._update_progress(50.0, text="Making callsites")
|
|
532
535
|
_, stackarg_offsets, removed_vvar_ids = self._make_callsites(ail_graph, stack_pointer_tracker=spt)
|
|
@@ -1010,13 +1013,15 @@ class Clinic(Analysis):
|
|
|
1010
1013
|
if node is None:
|
|
1011
1014
|
continue
|
|
1012
1015
|
successors = self._cfg.get_successors(node, excluding_fakeret=True, jumpkind="Ijk_Call")
|
|
1013
|
-
if len(successors) == 1
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1016
|
+
if len(successors) == 1:
|
|
1017
|
+
succ_addr = successors[0].addr
|
|
1018
|
+
if not self.project.is_hooked(succ_addr) or not isinstance(
|
|
1019
|
+
self.project.hooked_by(successors[0].addr), UnresolvableCallTarget
|
|
1020
|
+
):
|
|
1021
|
+
# found a single successor - replace the last statement
|
|
1022
|
+
new_last_stmt = last_stmt.copy()
|
|
1023
|
+
new_last_stmt.target = ailment.Expr.Const(None, None, successors[0].addr, last_stmt.target.bits)
|
|
1024
|
+
block.statements[-1] = new_last_stmt
|
|
1020
1025
|
|
|
1021
1026
|
elif isinstance(last_stmt, ailment.Stmt.Jump) and not isinstance(last_stmt.target, ailment.Expr.Const):
|
|
1022
1027
|
# indirect jump
|
|
@@ -2732,6 +2737,36 @@ class Clinic(Analysis):
|
|
|
2732
2737
|
|
|
2733
2738
|
return extra_regs
|
|
2734
2739
|
|
|
2740
|
+
def _rewrite_rust_probestack_call(self, ail_graph):
|
|
2741
|
+
for node in ail_graph:
|
|
2742
|
+
if not node.statements or ail_graph.out_degree[node] != 1:
|
|
2743
|
+
continue
|
|
2744
|
+
last_stmt = node.statements[-1]
|
|
2745
|
+
if isinstance(last_stmt, ailment.Stmt.Call) and isinstance(last_stmt.target, ailment.Expr.Const):
|
|
2746
|
+
func = (
|
|
2747
|
+
self.project.kb.functions.get_by_addr(last_stmt.target.value)
|
|
2748
|
+
if self.project.kb.functions.contains_addr(last_stmt.target.value)
|
|
2749
|
+
else None
|
|
2750
|
+
)
|
|
2751
|
+
if func is not None and func.info.get("is_rust_probestack", False) is True:
|
|
2752
|
+
# get rid of this call
|
|
2753
|
+
node.statements = node.statements[:-1]
|
|
2754
|
+
if self.project.arch.call_pushes_ret and node.statements:
|
|
2755
|
+
last_stmt = node.statements[-1]
|
|
2756
|
+
succ = next(iter(ail_graph.successors(node)))
|
|
2757
|
+
if (
|
|
2758
|
+
isinstance(last_stmt, ailment.Stmt.Store)
|
|
2759
|
+
and isinstance(last_stmt.addr, ailment.Expr.StackBaseOffset)
|
|
2760
|
+
and isinstance(last_stmt.addr.offset, int)
|
|
2761
|
+
and last_stmt.addr.offset < 0
|
|
2762
|
+
and isinstance(last_stmt.data, ailment.Expr.Const)
|
|
2763
|
+
and last_stmt.data.value == succ.addr
|
|
2764
|
+
):
|
|
2765
|
+
# remove the statement that pushes the return address
|
|
2766
|
+
node.statements = node.statements[:-1]
|
|
2767
|
+
break
|
|
2768
|
+
return ail_graph
|
|
2769
|
+
|
|
2735
2770
|
def _rewrite_alloca(self, ail_graph):
|
|
2736
2771
|
# pylint:disable=too-many-boolean-expressions
|
|
2737
2772
|
alloca_node = None
|
|
@@ -304,7 +304,7 @@ class AILMergeGraph:
|
|
|
304
304
|
end_pair_map = {}
|
|
305
305
|
end_pairs = set()
|
|
306
306
|
merge_to_end_pair = {}
|
|
307
|
-
for
|
|
307
|
+
for sblocks in self.merge_blocks_to_originals.values():
|
|
308
308
|
for sblock in sblocks:
|
|
309
309
|
if isinstance(sblock, AILBlockSplit) and sblock.original in self.merge_blocks_to_originals:
|
|
310
310
|
deletable_blocks.add(sblock.original)
|
|
@@ -429,7 +429,7 @@ class AILMergeGraph:
|
|
|
429
429
|
self.original_split_blocks[updated] = self.original_split_blocks[k]
|
|
430
430
|
del self.original_split_blocks[k]
|
|
431
431
|
|
|
432
|
-
for
|
|
432
|
+
for v in self.original_split_blocks.values():
|
|
433
433
|
for sblock in v:
|
|
434
434
|
for attr in ["up_split", "match_split", "down_split"]:
|
|
435
435
|
if getattr(sblock, attr) == original:
|
|
@@ -167,7 +167,7 @@ class DuplicationReverter(StructuringOptimizationPass):
|
|
|
167
167
|
|
|
168
168
|
def _reinsert_merged_candidate(self, ail_merge_graph: AILMergeGraph, candidate: tuple[Block, Block]) -> bool:
|
|
169
169
|
og_succs, og_preds = {}, {}
|
|
170
|
-
for
|
|
170
|
+
for original_blocks in ail_merge_graph.original_blocks.values():
|
|
171
171
|
# collect all the old edges
|
|
172
172
|
for og_block in original_blocks:
|
|
173
173
|
og_succs[og_block] = list(self.write_graph.successors(og_block))
|
|
@@ -364,7 +364,7 @@ class DuplicationReverter(StructuringOptimizationPass):
|
|
|
364
364
|
new_nodes[node] = new_node
|
|
365
365
|
|
|
366
366
|
# fixup every single jump target (before adding them to the graph)
|
|
367
|
-
for src, dst
|
|
367
|
+
for src, dst in graph.edges():
|
|
368
368
|
new_src = new_nodes[src]
|
|
369
369
|
new_dst = new_nodes[dst]
|
|
370
370
|
if new_dst is not dst:
|
|
@@ -263,7 +263,7 @@ class ITERegionConverter(OptimizationPass):
|
|
|
263
263
|
|
|
264
264
|
# is this the statement that we are looking for?
|
|
265
265
|
found_true_src_vvar, found_false_src_vvar = False, False
|
|
266
|
-
for
|
|
266
|
+
for _src, vvar in stmt.src.src_and_vvars:
|
|
267
267
|
if vvar is not None:
|
|
268
268
|
if vvar.varid == true_stmt_dst.varid:
|
|
269
269
|
found_true_src_vvar = True
|
|
@@ -557,7 +557,7 @@ class LoweredSwitchSimplifier(StructuringOptimizationPass):
|
|
|
557
557
|
varhash_to_caselists[v].append((cases, extra_cmp_nodes))
|
|
558
558
|
|
|
559
559
|
for v, caselists in list(varhash_to_caselists.items()):
|
|
560
|
-
for idx, (cases,
|
|
560
|
+
for idx, (cases, _redundant_nodes) in list(enumerate(caselists)):
|
|
561
561
|
# filter: each case value should only appear once
|
|
562
562
|
if len({case.value for case in cases}) != len(cases):
|
|
563
563
|
caselists[idx] = None
|
|
@@ -144,7 +144,7 @@ class StackCanarySimplifier(OptimizationPass):
|
|
|
144
144
|
nodes_to_process.append((pred, canary_check_stmt_idx, stack_chk_fail_caller, ret_node))
|
|
145
145
|
|
|
146
146
|
# Awesome. Now patch this function.
|
|
147
|
-
for pred,
|
|
147
|
+
for pred, _canary_check_stmt_idx, stack_chk_fail_caller, ret_node in nodes_to_process:
|
|
148
148
|
# Patch the pred so that it jumps to the one that is not stack_chk_fail_caller
|
|
149
149
|
pred_copy = pred.copy()
|
|
150
150
|
pred_copy.statements[-1] = ailment.Stmt.Jump(
|
|
@@ -1536,7 +1536,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1536
1536
|
full_graph.remove_edge(head, out_dst)
|
|
1537
1537
|
|
|
1538
1538
|
# fix full_graph if needed: remove successors that are no longer needed
|
|
1539
|
-
for
|
|
1539
|
+
for _out_src, out_dst in out_edges[1:]:
|
|
1540
1540
|
if out_dst in full_graph and out_dst not in graph and full_graph.in_degree[out_dst] == 0:
|
|
1541
1541
|
full_graph.remove_node(out_dst)
|
|
1542
1542
|
if out_dst in self._region.successors:
|
angr/analyses/disassembly.py
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
2
4
|
import logging
|
|
3
5
|
from collections import defaultdict
|
|
4
|
-
from typing import Union, Any
|
|
5
6
|
from collections.abc import Sequence
|
|
7
|
+
from typing import Union, Any
|
|
6
8
|
|
|
7
9
|
import pyvex
|
|
8
10
|
import archinfo
|
|
9
|
-
from angr.knowledge_plugins import Function
|
|
10
11
|
|
|
11
12
|
from . import Analysis
|
|
12
13
|
|
|
14
|
+
from angr.analyses import AnalysesHub
|
|
13
15
|
from angr.errors import AngrTypeError
|
|
16
|
+
from angr.knowledge_plugins import Function
|
|
14
17
|
from angr.utils.library import get_cpp_function_name
|
|
15
18
|
from angr.utils.formatting import ansi_color_enabled, ansi_color, add_edge_to_buffer
|
|
16
19
|
from angr.block import DisassemblerInsn, CapstoneInsn, SootBlockNode
|
|
17
20
|
from angr.codenode import BlockNode
|
|
18
21
|
from .disassembly_utils import decode_instruction
|
|
19
|
-
import contextlib
|
|
20
22
|
|
|
21
23
|
try:
|
|
22
24
|
from angr.engines import pcode
|
|
@@ -1295,6 +1297,4 @@ class Disassembly(Analysis):
|
|
|
1295
1297
|
return "\n".join(buf)
|
|
1296
1298
|
|
|
1297
1299
|
|
|
1298
|
-
from angr.analyses import AnalysesHub
|
|
1299
|
-
|
|
1300
1300
|
AnalysesHub.register_default("Disassembly", Disassembly)
|