angr 9.2.120__py3-none-manylinux2014_x86_64.whl → 9.2.122__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/cfg/cfg_fast.py +2 -1
- angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
- angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +2 -0
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +10 -6
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +138 -367
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_got.py +148 -0
- angr/analyses/decompiler/callsite_maker.py +11 -1
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +20 -0
- angr/analyses/typehoon/typevars.py +37 -16
- angr/angrdb/db.py +1 -1
- angr/block.py +9 -1
- angr/calling_conventions.py +1 -1
- angr/engines/engine.py +8 -15
- angr/engines/pcode/lifter.py +8 -0
- angr/engines/successors.py +1 -1
- angr/engines/vex/claripy/ccall.py +1 -1
- angr/engines/vex/claripy/datalayer.py +7 -10
- angr/engines/vex/heavy/actions.py +19 -24
- angr/engines/vex/heavy/heavy.py +7 -1
- angr/engines/vex/lifter.py +3 -1
- angr/engines/vex/light/light.py +2 -2
- angr/factory.py +5 -0
- angr/knowledge_plugins/cfg/memory_data.py +1 -0
- angr/lib/angr_native.so +0 -0
- angr/protos/cfg_pb2.py +23 -15
- angr/protos/function_pb2.py +19 -21
- angr/protos/primitives_pb2.py +46 -112
- angr/protos/variables_pb2.py +38 -114
- angr/protos/xrefs_pb2.py +17 -18
- angr/sim_state.py +2 -78
- angr/sim_type.py +53 -18
- angr/state_plugins/solver.py +72 -15
- angr/storage/__init__.py +1 -2
- angr/storage/memory_mixins/__init__.py +5 -160
- angr/storage/memory_mixins/actions_mixin.py +1 -1
- angr/storage/memory_mixins/address_concretization_mixin.py +1 -1
- angr/storage/memory_mixins/bvv_conversion_mixin.py +1 -1
- angr/storage/memory_mixins/clouseau_mixin.py +2 -1
- angr/storage/memory_mixins/conditional_store_mixin.py +1 -1
- angr/storage/memory_mixins/convenient_mappings_mixin.py +1 -1
- angr/storage/memory_mixins/default_filler_mixin.py +1 -1
- angr/storage/memory_mixins/dirty_addrs_mixin.py +2 -1
- angr/storage/memory_mixins/hex_dumper_mixin.py +1 -1
- angr/storage/memory_mixins/javavm_memory_mixin.py +1 -1
- angr/storage/memory_mixins/keyvalue_memory_mixin.py +1 -1
- angr/storage/memory_mixins/label_merger_mixin.py +1 -1
- angr/storage/memory_mixins/memory_mixin.py +163 -0
- angr/storage/memory_mixins/multi_value_merger_mixin.py +1 -1
- angr/storage/memory_mixins/name_resolution_mixin.py +3 -1
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -1
- angr/storage/memory_mixins/paged_memory/paged_memory_multivalue_mixin.py +2 -1
- angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/history_tracking_mixin.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +2 -1
- angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/refcount_mixin.py +2 -1
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +1 -1
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +1 -2
- angr/storage/memory_mixins/regioned_memory/region_category_mixin.py +2 -1
- angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +1 -1
- angr/storage/memory_mixins/regioned_memory/regioned_address_concretization_mixin.py +1 -1
- angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +2 -2
- angr/storage/memory_mixins/simple_interface_mixin.py +2 -1
- angr/storage/memory_mixins/simplification_mixin.py +2 -1
- angr/storage/memory_mixins/size_resolution_mixin.py +1 -1
- angr/storage/memory_mixins/slotted_memory.py +2 -2
- angr/storage/memory_mixins/smart_find_mixin.py +1 -1
- angr/storage/memory_mixins/symbolic_merger_mixin.py +2 -1
- angr/storage/memory_mixins/top_merger_mixin.py +3 -2
- angr/storage/memory_mixins/underconstrained_mixin.py +4 -2
- angr/storage/memory_mixins/unwrapper_mixin.py +2 -1
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/METADATA +7 -7
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/RECORD +78 -76
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/LICENSE +0 -0
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/WHEEL +0 -0
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/entry_points.txt +0 -0
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/top_level.txt +0 -0
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
# pylint:disable=too-many-boolean-expressions,global-statement
|
|
1
|
+
# pylint:disable=too-many-boolean-expressions,global-statement,too-many-positional-arguments
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
import logging
|
|
5
|
+
from enum import Enum
|
|
5
6
|
|
|
6
7
|
import archinfo
|
|
7
|
-
import claripy
|
|
8
8
|
import pyvex
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
from angr import options, BP_BEFORE
|
|
12
11
|
from angr.blade import Blade
|
|
13
|
-
from angr.annocfg import AnnotatedCFG
|
|
14
|
-
from angr.exploration_techniques import Slicecutor
|
|
15
12
|
from angr.utils.constants import DEFAULT_STATEMENT
|
|
16
13
|
from .resolver import IndirectJumpResolver
|
|
17
14
|
|
|
@@ -22,14 +19,15 @@ if TYPE_CHECKING:
|
|
|
22
19
|
l = logging.getLogger(name=__name__)
|
|
23
20
|
|
|
24
21
|
PROFILING = False
|
|
25
|
-
|
|
22
|
+
HITS_CASE_1, HITS_CASE_2, MISSES = 0, 0, 0
|
|
26
23
|
|
|
27
24
|
|
|
28
25
|
def enable_profiling():
|
|
29
|
-
global PROFILING,
|
|
26
|
+
global PROFILING, HITS_CASE_1, HITS_CASE_2, MISSES
|
|
27
|
+
|
|
30
28
|
PROFILING = True
|
|
31
|
-
HITS_CASE_0 = 0
|
|
32
29
|
HITS_CASE_1 = 0
|
|
30
|
+
HITS_CASE_2 = 0
|
|
33
31
|
MISSES = 0
|
|
34
32
|
|
|
35
33
|
|
|
@@ -38,16 +36,14 @@ def disable_profiling():
|
|
|
38
36
|
PROFILING = False
|
|
39
37
|
|
|
40
38
|
|
|
41
|
-
class
|
|
39
|
+
class Case2Result(Enum):
|
|
42
40
|
"""
|
|
43
|
-
|
|
41
|
+
Describes the result of resolving case 2 function calls.
|
|
44
42
|
"""
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def overwrite_tmp_value(self, state):
|
|
50
|
-
state.inspect.tmp_write_expr = claripy.BVV(self.gp_value, state.arch.bits)
|
|
44
|
+
SUCCESS = 0
|
|
45
|
+
FAILURE = 1
|
|
46
|
+
RESUME = 2
|
|
51
47
|
|
|
52
48
|
|
|
53
49
|
class MipsElfFastResolver(IndirectJumpResolver):
|
|
@@ -76,10 +72,14 @@ class MipsElfFastResolver(IndirectJumpResolver):
|
|
|
76
72
|
:return: If it was resolved and targets alongside it
|
|
77
73
|
:rtype: tuple
|
|
78
74
|
"""
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
global MISSES
|
|
76
|
+
|
|
77
|
+
resolved, resolved_targets = self._resolve(cfg, addr, func_addr, block, jumpkind, max_level=2)
|
|
78
|
+
if resolved:
|
|
79
|
+
return resolved, resolved_targets
|
|
80
|
+
|
|
81
|
+
if PROFILING:
|
|
82
|
+
MISSES += 1
|
|
83
83
|
return False, []
|
|
84
84
|
|
|
85
85
|
def _resolve(self, cfg, addr, func_addr, block, jumpkind, max_level): # pylint:disable=unused-argument
|
|
@@ -96,16 +96,15 @@ class MipsElfFastResolver(IndirectJumpResolver):
|
|
|
96
96
|
:rtype: tuple
|
|
97
97
|
"""
|
|
98
98
|
|
|
99
|
-
global
|
|
100
|
-
|
|
101
|
-
project = self.project
|
|
99
|
+
global HITS_CASE_1, HITS_CASE_2
|
|
102
100
|
|
|
101
|
+
func = cfg.kb.functions.function(addr=func_addr)
|
|
103
102
|
b = Blade(
|
|
104
103
|
cfg.graph,
|
|
105
104
|
addr,
|
|
106
105
|
-1,
|
|
107
106
|
cfg=cfg,
|
|
108
|
-
project=project,
|
|
107
|
+
project=self.project,
|
|
109
108
|
ignore_sp=True,
|
|
110
109
|
ignore_bp=True,
|
|
111
110
|
ignored_regs=("gp",),
|
|
@@ -115,11 +114,10 @@ class MipsElfFastResolver(IndirectJumpResolver):
|
|
|
115
114
|
include_imarks=False,
|
|
116
115
|
)
|
|
117
116
|
|
|
118
|
-
func = cfg.kb.functions.function(addr=func_addr)
|
|
119
117
|
gp_value = func.info.get("gp", None)
|
|
120
118
|
|
|
121
119
|
# see if gp is used on this slice at all
|
|
122
|
-
gp_used = self._is_gp_used_on_slice(project, b)
|
|
120
|
+
gp_used = self._is_gp_used_on_slice(self.project, b)
|
|
123
121
|
if gp_used and gp_value is None:
|
|
124
122
|
# this might a special case: gp is only used once in this function, and it can be initialized right
|
|
125
123
|
# before its use site.
|
|
@@ -128,362 +126,135 @@ class MipsElfFastResolver(IndirectJumpResolver):
|
|
|
128
126
|
l.warning("Failed to determine value of register gp for function %#x.", func.addr)
|
|
129
127
|
return False, []
|
|
130
128
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
target = self.
|
|
139
|
-
if
|
|
129
|
+
# we support two cases:
|
|
130
|
+
# Case 1. t9 is set in the current block, and jalr $t9 at the end of the same block.
|
|
131
|
+
# Case 2. t9 is set in both predecessor blocks, and jalr $t9 at the end of the current block.
|
|
132
|
+
|
|
133
|
+
block_addrs = {block_addr for block_addr, _ in b.slice}
|
|
134
|
+
if len(block_addrs) == 2 and addr in block_addrs:
|
|
135
|
+
first_block_addr = next(iter(block_addrs - {addr}))
|
|
136
|
+
r, target = self._resolve_case_2(first_block_addr, block, func_addr, gp_value, cfg)
|
|
137
|
+
if r == Case2Result.SUCCESS:
|
|
140
138
|
if PROFILING:
|
|
141
|
-
|
|
142
|
-
# print(f"hit/miss: {HITS_CASE_0 + HITS_CASE_1}/{MISSES}, {HITS_CASE_0}|{HITS_CASE_1}")
|
|
139
|
+
HITS_CASE_2 += 1
|
|
143
140
|
return True, [target]
|
|
144
|
-
|
|
145
|
-
if PROFILING:
|
|
146
|
-
MISSES += 1
|
|
147
|
-
# print(f"hit/miss: {HITS_CASE_0 + HITS_CASE_1}/{MISSES}, {HITS_CASE_0}|{HITS_CASE_1}")
|
|
148
|
-
|
|
149
|
-
sources = [n for n in b.slice.nodes() if b.slice.in_degree(n) == 0]
|
|
150
|
-
if not sources:
|
|
151
|
-
return False, []
|
|
152
|
-
|
|
153
|
-
source = sources[0]
|
|
154
|
-
source_addr = source[0]
|
|
155
|
-
annotated_cfg = AnnotatedCFG(project, None, detect_loops=False)
|
|
156
|
-
annotated_cfg.from_digraph(b.slice)
|
|
157
|
-
|
|
158
|
-
state = project.factory.blank_state(
|
|
159
|
-
addr=source_addr,
|
|
160
|
-
mode="fastpath",
|
|
161
|
-
remove_options=options.refs,
|
|
162
|
-
# suppress unconstrained stack reads for `gp`
|
|
163
|
-
add_options={
|
|
164
|
-
options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS,
|
|
165
|
-
options.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
|
|
166
|
-
options.NO_CROSS_INSN_OPT,
|
|
167
|
-
},
|
|
168
|
-
)
|
|
169
|
-
state.regs._t9 = func_addr
|
|
170
|
-
|
|
171
|
-
if gp_used:
|
|
172
|
-
# Special handling for cases where `gp` is stored on the stack
|
|
173
|
-
gp_offset = project.arch.registers["gp"][0]
|
|
174
|
-
self._set_gp_load_callback(state, b, project, gp_offset, gp_value)
|
|
175
|
-
state.regs._gp = gp_value
|
|
176
|
-
|
|
177
|
-
simgr = self.project.factory.simulation_manager(state)
|
|
178
|
-
simgr.use_technique(Slicecutor(annotated_cfg, force_sat=True))
|
|
179
|
-
simgr.run()
|
|
180
|
-
|
|
181
|
-
if simgr.cut:
|
|
182
|
-
# pick the successor that is cut right after executing `addr`
|
|
183
|
-
try:
|
|
184
|
-
target_state = next(iter(cut for cut in simgr.cut if cut.history.addr == addr))
|
|
185
|
-
except StopIteration:
|
|
186
|
-
l.info("Indirect jump at %#x cannot be resolved by %s.", addr, repr(self))
|
|
141
|
+
if r == Case2Result.FAILURE:
|
|
187
142
|
return False, []
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if self._is_target_valid(cfg, target) and target != func_addr:
|
|
191
|
-
l.debug("Indirect jump at %#x is resolved to target %#x.", addr, target)
|
|
192
|
-
return True, [target]
|
|
143
|
+
# otherwise, we need to resume the analysis
|
|
193
144
|
|
|
194
|
-
|
|
195
|
-
|
|
145
|
+
target = self._resolve_case_1(addr, block, func_addr, gp_value, cfg)
|
|
146
|
+
if target is not None:
|
|
147
|
+
if PROFILING:
|
|
148
|
+
HITS_CASE_1 += 1
|
|
149
|
+
return True, [target]
|
|
196
150
|
|
|
197
|
-
|
|
151
|
+
# no luck
|
|
198
152
|
return False, []
|
|
199
153
|
|
|
200
|
-
def
|
|
201
|
-
#
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (
|
|
271
|
-
not isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
272
|
-
or stmt.tmp != addr_tmp
|
|
273
|
-
or not isinstance(stmt.data, pyvex.IRExpr.Binop)
|
|
274
|
-
or stmt.data.op != "Iop_Add32"
|
|
275
|
-
or not isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp)
|
|
276
|
-
or not isinstance(stmt.data.args[1], pyvex.IRExpr.Const)
|
|
277
|
-
):
|
|
278
|
-
return None
|
|
279
|
-
add_tmp = stmt.data.args[0].tmp
|
|
280
|
-
add_const = stmt.data.args[1].con.value
|
|
281
|
-
|
|
282
|
-
# A
|
|
283
|
-
previous_node = self._previous_node(blade, previous_node)
|
|
284
|
-
if previous_node is None:
|
|
285
|
-
return None
|
|
286
|
-
stmt = end_block.statements[previous_node[1]]
|
|
287
|
-
if (
|
|
288
|
-
not isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
289
|
-
or stmt.tmp != add_tmp
|
|
290
|
-
or not isinstance(stmt.data, pyvex.IRExpr.Get)
|
|
291
|
-
):
|
|
292
|
-
return None
|
|
293
|
-
if stmt.data.offset != self.project.arch.registers["gp"][0]:
|
|
294
|
-
return None
|
|
295
|
-
|
|
296
|
-
# matching complete
|
|
297
|
-
addr = (gp + add_const) & 0xFFFF_FFFF
|
|
298
|
-
try:
|
|
299
|
-
return self.project.loader.memory.unpack_word(addr, size=4)
|
|
300
|
-
except KeyError:
|
|
301
|
-
return None
|
|
302
|
-
|
|
303
|
-
def _try_handle_simple_case_1(self, gp: int, blade: Blade) -> int | None:
|
|
304
|
-
# we only attempt to support the following case:
|
|
305
|
-
# + A | t22 = GET:I32(gp)
|
|
306
|
-
# + B | t21 = Add32(t22,0xffff8020)
|
|
307
|
-
# + C | t23 = LDbe:I32(t21)
|
|
308
|
-
# + D | PUT(t9) = t23
|
|
309
|
-
# + E | t27 = GET:I32(t9)
|
|
310
|
-
# + F | t26 = Add32(t27,0x00007cec)
|
|
311
|
-
# + G | PUT(t9) = t26
|
|
312
|
-
# + H | t4 = GET:I32(t9)
|
|
313
|
-
# + Next: t4
|
|
314
|
-
|
|
315
|
-
nodes_with_no_outedges = []
|
|
316
|
-
for node in blade.slice.nodes():
|
|
317
|
-
if blade.slice.out_degree(node) == 0:
|
|
318
|
-
nodes_with_no_outedges.append(node)
|
|
319
|
-
if len(nodes_with_no_outedges) != 1:
|
|
320
|
-
return None
|
|
321
|
-
|
|
322
|
-
end_node = nodes_with_no_outedges[0]
|
|
323
|
-
if end_node[-1] != DEFAULT_STATEMENT:
|
|
324
|
-
return None
|
|
325
|
-
|
|
326
|
-
end_block = self.project.factory.block(end_node[0], cross_insn_opt=blade._cross_insn_opt).vex
|
|
327
|
-
if not isinstance(end_block.next, pyvex.IRExpr.RdTmp):
|
|
328
|
-
return None
|
|
329
|
-
next_tmp = end_block.next.tmp
|
|
330
|
-
|
|
331
|
-
# step backward
|
|
332
|
-
|
|
333
|
-
# H
|
|
334
|
-
previous_node = self._previous_node(blade, end_node)
|
|
335
|
-
if previous_node is None:
|
|
336
|
-
return None
|
|
337
|
-
stmt = end_block.statements[previous_node[1]]
|
|
338
|
-
if not isinstance(stmt, pyvex.IRStmt.WrTmp) or not isinstance(stmt.data, pyvex.IRExpr.Get):
|
|
339
|
-
return None
|
|
340
|
-
if stmt.tmp != next_tmp:
|
|
341
|
-
return None
|
|
342
|
-
if stmt.data.offset != self.project.arch.registers["t9"][0]:
|
|
343
|
-
return None
|
|
344
|
-
|
|
345
|
-
# G
|
|
346
|
-
previous_node = self._previous_node(blade, previous_node)
|
|
347
|
-
if previous_node is None:
|
|
348
|
-
return None
|
|
349
|
-
stmt = end_block.statements[previous_node[1]]
|
|
350
|
-
if not isinstance(stmt, pyvex.IRStmt.Put) or not isinstance(stmt.data, pyvex.IRExpr.RdTmp):
|
|
351
|
-
return None
|
|
352
|
-
if stmt.offset != self.project.arch.registers["t9"][0]:
|
|
353
|
-
return None
|
|
354
|
-
t9_tmp_G = stmt.data.tmp
|
|
355
|
-
|
|
356
|
-
# F
|
|
357
|
-
previous_node = self._previous_node(blade, previous_node)
|
|
358
|
-
if previous_node is None:
|
|
359
|
-
return None
|
|
360
|
-
stmt = end_block.statements[previous_node[1]]
|
|
361
|
-
if (
|
|
362
|
-
not isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
363
|
-
or stmt.tmp != t9_tmp_G
|
|
364
|
-
or not isinstance(stmt.data, pyvex.IRExpr.Binop)
|
|
365
|
-
or stmt.data.op != "Iop_Add32"
|
|
366
|
-
or not isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp)
|
|
367
|
-
or not isinstance(stmt.data.args[1], pyvex.IRExpr.Const)
|
|
368
|
-
):
|
|
369
|
-
return None
|
|
370
|
-
t9_tmp_F = stmt.data.args[0].tmp
|
|
371
|
-
t9_add_const = stmt.data.args[1].con.value
|
|
372
|
-
|
|
373
|
-
# E
|
|
374
|
-
previous_node = self._previous_node(blade, previous_node)
|
|
375
|
-
if previous_node is None:
|
|
376
|
-
return None
|
|
377
|
-
stmt = end_block.statements[previous_node[1]]
|
|
378
|
-
if not isinstance(stmt, pyvex.IRStmt.WrTmp) or not isinstance(stmt.data, pyvex.IRExpr.Get):
|
|
379
|
-
return None
|
|
380
|
-
if stmt.tmp != t9_tmp_F:
|
|
381
|
-
return None
|
|
382
|
-
if stmt.data.offset != self.project.arch.registers["t9"][0]:
|
|
383
|
-
return None
|
|
384
|
-
|
|
385
|
-
# D
|
|
386
|
-
previous_node = self._previous_node(blade, previous_node)
|
|
387
|
-
if previous_node is None:
|
|
388
|
-
return None
|
|
389
|
-
stmt = end_block.statements[previous_node[1]]
|
|
390
|
-
if not isinstance(stmt, pyvex.IRStmt.Put) or not isinstance(stmt.data, pyvex.IRExpr.RdTmp):
|
|
391
|
-
return None
|
|
392
|
-
if stmt.offset != self.project.arch.registers["t9"][0]:
|
|
393
|
-
return None
|
|
394
|
-
t9_tmp_D = stmt.data.tmp
|
|
395
|
-
|
|
396
|
-
# C
|
|
397
|
-
previous_node = self._previous_node(blade, previous_node)
|
|
398
|
-
if previous_node is None:
|
|
399
|
-
return None
|
|
400
|
-
stmt = end_block.statements[previous_node[1]]
|
|
401
|
-
if (
|
|
402
|
-
not isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
403
|
-
or not isinstance(stmt.data, pyvex.IRExpr.Load)
|
|
404
|
-
or not isinstance(stmt.data.addr, pyvex.IRExpr.RdTmp)
|
|
405
|
-
):
|
|
406
|
-
return None
|
|
407
|
-
if stmt.tmp != t9_tmp_D:
|
|
408
|
-
return None
|
|
409
|
-
addr_tmp = stmt.data.addr.tmp
|
|
410
|
-
|
|
411
|
-
# B
|
|
412
|
-
previous_node = self._previous_node(blade, previous_node)
|
|
413
|
-
if previous_node is None:
|
|
414
|
-
return None
|
|
415
|
-
stmt = end_block.statements[previous_node[1]]
|
|
416
|
-
if (
|
|
417
|
-
not isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
418
|
-
or stmt.tmp != addr_tmp
|
|
419
|
-
or not isinstance(stmt.data, pyvex.IRExpr.Binop)
|
|
420
|
-
or stmt.data.op != "Iop_Add32"
|
|
421
|
-
or not isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp)
|
|
422
|
-
or not isinstance(stmt.data.args[1], pyvex.IRExpr.Const)
|
|
423
|
-
):
|
|
424
|
-
return None
|
|
425
|
-
add_tmp = stmt.data.args[0].tmp
|
|
426
|
-
add_const = stmt.data.args[1].con.value
|
|
154
|
+
def _resolve_case_1(self, addr: int, block: pyvex.IRSB, func_addr: int, gp_value: int, cfg) -> int | None:
|
|
155
|
+
# lift the block again with the correct setting
|
|
156
|
+
first_irsb = self.project.factory.block(
|
|
157
|
+
addr,
|
|
158
|
+
size=block.size,
|
|
159
|
+
collect_data_refs=False,
|
|
160
|
+
const_prop=True,
|
|
161
|
+
cross_insn_opt=False,
|
|
162
|
+
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
|
+
],
|
|
167
|
+
).vex_nostmt
|
|
168
|
+
|
|
169
|
+
if not isinstance(first_irsb.next, pyvex.IRExpr.RdTmp):
|
|
170
|
+
return None
|
|
171
|
+
target_tmp = first_irsb.next.tmp
|
|
172
|
+
if first_irsb.const_vals is None:
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
# find the value of the next tmp
|
|
176
|
+
for cv in first_irsb.const_vals:
|
|
177
|
+
if cv.tmp == target_tmp:
|
|
178
|
+
target = cv.value
|
|
179
|
+
if self._is_target_valid(cfg, target):
|
|
180
|
+
return target
|
|
181
|
+
break
|
|
182
|
+
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
def _resolve_case_2(
|
|
186
|
+
self, first_block_addr: int, second_block: pyvex.IRSB, func_addr: int, gp_value: int, cfg
|
|
187
|
+
) -> tuple[Case2Result, int | None]:
|
|
188
|
+
jump_target_reg = self._get_jump_target_reg(second_block)
|
|
189
|
+
if jump_target_reg is None:
|
|
190
|
+
return Case2Result.FAILURE, None
|
|
191
|
+
last_reg_setting_tmp = self._get_last_reg_setting_tmp(second_block, jump_target_reg)
|
|
192
|
+
if last_reg_setting_tmp is not None:
|
|
193
|
+
# the register (t9) is set in this block - we can resolve the jump target using only the current block
|
|
194
|
+
return Case2Result.RESUME, None
|
|
195
|
+
|
|
196
|
+
# lift the first block again with the correct setting
|
|
197
|
+
first_irsb = self.project.factory.block(
|
|
198
|
+
first_block_addr,
|
|
199
|
+
cross_insn_opt=False,
|
|
200
|
+
collect_data_refs=False,
|
|
201
|
+
const_prop=True,
|
|
202
|
+
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
|
+
],
|
|
207
|
+
).vex_nostmt
|
|
208
|
+
|
|
209
|
+
last_reg_setting_tmp = self._get_last_reg_setting_tmp(first_irsb, jump_target_reg)
|
|
210
|
+
if last_reg_setting_tmp is None:
|
|
211
|
+
return Case2Result.FAILURE, None
|
|
212
|
+
|
|
213
|
+
# find the value of the next tmp
|
|
214
|
+
if first_irsb.const_vals is None:
|
|
215
|
+
return Case2Result.FAILURE, None
|
|
216
|
+
for cv in first_irsb.const_vals:
|
|
217
|
+
if cv.tmp == last_reg_setting_tmp:
|
|
218
|
+
target = cv.value
|
|
219
|
+
if self._is_target_valid(cfg, target):
|
|
220
|
+
return Case2Result.SUCCESS, target
|
|
221
|
+
break
|
|
222
|
+
|
|
223
|
+
return Case2Result.FAILURE, None
|
|
427
224
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
if
|
|
431
|
-
return None
|
|
432
|
-
stmt = end_block.statements[previous_node[1]]
|
|
433
|
-
if (
|
|
434
|
-
not isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
435
|
-
or stmt.tmp != add_tmp
|
|
436
|
-
or not isinstance(stmt.data, pyvex.IRExpr.Get)
|
|
437
|
-
):
|
|
225
|
+
@staticmethod
|
|
226
|
+
def _get_jump_target_reg(block: pyvex.IRSB) -> int | None:
|
|
227
|
+
if block.jumpkind != "Ijk_Call":
|
|
438
228
|
return None
|
|
439
|
-
if
|
|
229
|
+
if not isinstance(block.next, pyvex.IRExpr.RdTmp):
|
|
440
230
|
return None
|
|
231
|
+
next_tmp = block.next.tmp
|
|
441
232
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
233
|
+
for stmt in reversed(block.statements):
|
|
234
|
+
if (
|
|
235
|
+
isinstance(stmt, pyvex.IRStmt.Put)
|
|
236
|
+
and isinstance(stmt.data, pyvex.IRExpr.RdTmp)
|
|
237
|
+
and stmt.data.tmp == next_tmp
|
|
238
|
+
):
|
|
239
|
+
return stmt.offset
|
|
240
|
+
if (
|
|
241
|
+
isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
242
|
+
and stmt.tmp == next_tmp
|
|
243
|
+
and isinstance(stmt.data, pyvex.IRExpr.Get)
|
|
244
|
+
):
|
|
245
|
+
return stmt.data.offset
|
|
449
246
|
|
|
450
|
-
|
|
451
|
-
def _previous_node(blade: Blade, curr_node: tuple[int, int]) -> tuple[int, int] | None:
|
|
452
|
-
if blade.slice.in_degree(curr_node) != 1:
|
|
453
|
-
return None
|
|
454
|
-
nn = next(iter(blade.slice.predecessors(curr_node)))
|
|
455
|
-
if nn[0] != curr_node[0]:
|
|
456
|
-
return None
|
|
457
|
-
return nn
|
|
247
|
+
return None
|
|
458
248
|
|
|
459
249
|
@staticmethod
|
|
460
|
-
def
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
isinstance(stmt, pyvex.IRStmt.Put)
|
|
469
|
-
and stmt.offset == gp_offset
|
|
470
|
-
and isinstance(stmt.data, pyvex.IRExpr.RdTmp)
|
|
471
|
-
):
|
|
472
|
-
tmp_offset = stmt.data.tmp # pylint:disable=cell-var-from-loop
|
|
473
|
-
if tmps.get(tmp_offset) == "stack":
|
|
474
|
-
# found the load from stack
|
|
475
|
-
# we must make sure value of that temporary variable equals to the correct gp value
|
|
476
|
-
state.inspect.make_breakpoint(
|
|
477
|
-
"tmp_write",
|
|
478
|
-
when=BP_BEFORE,
|
|
479
|
-
condition=(
|
|
480
|
-
lambda s, bbl_addr_=block_addr_in_slice, tmp_offset_=tmp_offset: s.scratch.bbl_addr
|
|
481
|
-
== bbl_addr_
|
|
482
|
-
and s.inspect.tmp_write_num == tmp_offset_
|
|
483
|
-
),
|
|
484
|
-
action=OverwriteTmpValueCallback(gp_value).overwrite_tmp_value,
|
|
485
|
-
)
|
|
486
|
-
break
|
|
250
|
+
def _get_last_reg_setting_tmp(block: pyvex.IRSB, target_reg: int) -> int | None:
|
|
251
|
+
for stmt in reversed(block.statements):
|
|
252
|
+
if isinstance(stmt, pyvex.IRStmt.Put) and stmt.offset == target_reg:
|
|
253
|
+
if isinstance(stmt.data, pyvex.IRExpr.RdTmp):
|
|
254
|
+
return stmt.data.tmp
|
|
255
|
+
return None
|
|
256
|
+
|
|
257
|
+
return None
|
|
487
258
|
|
|
488
259
|
@staticmethod
|
|
489
260
|
def _is_gp_used_on_slice(project, b: Blade) -> bool:
|