angr 9.2.114__py3-none-manylinux2014_aarch64.whl → 9.2.115__py3-none-manylinux2014_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/__main__.py +2 -2
- angr/analyses/cfg/cfg_fast.py +1 -1
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +2 -2
- angr/analyses/decompiler/decompilation_options.py +2 -12
- angr/analyses/decompiler/decompiler.py +14 -3
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +3 -0
- angr/analyses/decompiler/optimization_passes/cross_jump_reverter.py +0 -3
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +2 -3
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +9 -2
- angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +2 -0
- angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +2 -0
- angr/analyses/decompiler/structuring/__init__.py +6 -2
- angr/analyses/decompiler/structuring/phoenix.py +28 -91
- angr/analyses/decompiler/structuring/recursive_structurer.py +0 -3
- angr/analyses/decompiler/structuring/sailr.py +111 -0
- angr/analyses/decompiler/structuring/structurer_base.py +0 -2
- angr/analyses/reaching_definitions/function_handler.py +11 -1
- angr/analyses/reaching_definitions/function_handler_library/__init__.py +0 -0
- angr/analyses/reaching_definitions/function_handler_library/stdio.py +260 -0
- angr/analyses/reaching_definitions/function_handler_library/stdlib.py +151 -0
- angr/analyses/reaching_definitions/function_handler_library/string.py +93 -0
- angr/analyses/reaching_definitions/function_handler_library/unistd.py +23 -0
- angr/analyses/reaching_definitions/rd_state.py +3 -1
- angr/analyses/vfg.py +13 -14
- angr/code_location.py +4 -4
- angr/engines/vex/heavy/heavy.py +1 -1
- angr/procedures/libc/strlen.py +5 -2
- angr/sim_variable.py +3 -18
- angr/state_plugins/solver.py +3 -9
- angr/storage/memory_mixins/address_concretization_mixin.py +1 -1
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
- angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +5 -5
- angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +3 -3
- {angr-9.2.114.dist-info → angr-9.2.115.dist-info}/METADATA +6 -6
- {angr-9.2.114.dist-info → angr-9.2.115.dist-info}/RECORD +40 -34
- {angr-9.2.114.dist-info → angr-9.2.115.dist-info}/WHEEL +1 -1
- {angr-9.2.114.dist-info → angr-9.2.115.dist-info}/LICENSE +0 -0
- {angr-9.2.114.dist-info → angr-9.2.115.dist-info}/entry_points.txt +0 -0
- {angr-9.2.114.dist-info → angr-9.2.115.dist-info}/top_level.txt +0 -0
|
@@ -254,15 +254,25 @@ class FunctionCallDataUnwrapped(FunctionCallData):
|
|
|
254
254
|
return inner
|
|
255
255
|
|
|
256
256
|
|
|
257
|
+
def _mk_wrapper(func, iself):
|
|
258
|
+
return lambda *args, **kwargs: func(iself, *args, **kwargs)
|
|
259
|
+
|
|
260
|
+
|
|
257
261
|
# pylint: disable=unused-argument, no-self-use
|
|
258
262
|
class FunctionHandler:
|
|
259
263
|
"""
|
|
260
264
|
A mechanism for summarizing a function call's effect on a program for ReachingDefinitionsAnalysis.
|
|
261
265
|
"""
|
|
262
266
|
|
|
263
|
-
def __init__(self, interfunction_level: int = 0):
|
|
267
|
+
def __init__(self, interfunction_level: int = 0, extra_impls: Iterable["FunctionHandler"] | None = None):
|
|
264
268
|
self.interfunction_level: int = interfunction_level
|
|
265
269
|
|
|
270
|
+
if extra_impls is not None:
|
|
271
|
+
for extra_handler in extra_impls:
|
|
272
|
+
for name, func in vars(extra_handler).items():
|
|
273
|
+
if name.startswith("handle_impl_"):
|
|
274
|
+
setattr(self, name, _mk_wrapper(func, self))
|
|
275
|
+
|
|
266
276
|
def hook(self, analysis: "ReachingDefinitionsAnalysis") -> "FunctionHandler":
|
|
267
277
|
"""
|
|
268
278
|
Attach this instance of the function handler to an instance of RDA.
|
|
File without changes
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import random
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import Iterable
|
|
5
|
+
|
|
6
|
+
import archinfo
|
|
7
|
+
import claripy
|
|
8
|
+
|
|
9
|
+
from angr.analyses.reaching_definitions.function_handler import FunctionCallDataUnwrapped, FunctionHandler
|
|
10
|
+
from angr.analyses.reaching_definitions.rd_state import ReachingDefinitionsState
|
|
11
|
+
from angr.knowledge_plugins.key_definitions.atoms import Atom
|
|
12
|
+
from angr.knowledge_plugins.key_definitions.live_definitions import DerefSize
|
|
13
|
+
from angr.sim_type import SimType, SimTypeBottom, SimTypeChar, SimTypeFunction, SimTypeInt, SimTypePointer
|
|
14
|
+
from angr.storage.memory_mixins.paged_memory.pages.multi_values import MultiValues
|
|
15
|
+
|
|
16
|
+
# pylint: disable=no-self-use,missing-class-docstring,unused-argument
|
|
17
|
+
|
|
18
|
+
_l = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class StdoutAtom(Atom):
|
|
22
|
+
def __init__(self, sink: str):
|
|
23
|
+
self.nonce = random.randint(0, 999999999999)
|
|
24
|
+
self.sink = sink
|
|
25
|
+
super().__init__(1)
|
|
26
|
+
|
|
27
|
+
def _identity(self):
|
|
28
|
+
return (self.nonce,)
|
|
29
|
+
|
|
30
|
+
def __repr__(self):
|
|
31
|
+
return f"<StdoutAtom {self.sink}>"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class StdinAtom(Atom):
|
|
35
|
+
def __init__(self, source: str):
|
|
36
|
+
self.nonce = random.randint(0, 999999999999)
|
|
37
|
+
self.source = source
|
|
38
|
+
super().__init__(1)
|
|
39
|
+
|
|
40
|
+
def _identity(self):
|
|
41
|
+
return (self.nonce,)
|
|
42
|
+
|
|
43
|
+
def __repr__(self):
|
|
44
|
+
return f"<StdinAtom {self.source}>"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def parse_format_string(format_string: str) -> tuple[list[str | int], list[SimType], list[str]]:
|
|
48
|
+
result_pieces: list[str | int] = []
|
|
49
|
+
result_types: list[SimType] = []
|
|
50
|
+
result_specs: list[str] = []
|
|
51
|
+
|
|
52
|
+
last_piece = 0
|
|
53
|
+
idx = 0
|
|
54
|
+
for argspec in re.finditer(r"\%([0 #+-]?[0-9*]*\.?\d*([hl]{0,2}|[jztL])?[diuoxXeEfgGaAcpsSn%])", format_string):
|
|
55
|
+
start, end = argspec.span()
|
|
56
|
+
if format_string[end - 1] == "%":
|
|
57
|
+
continue
|
|
58
|
+
if start != last_piece:
|
|
59
|
+
result_pieces.append(format_string[last_piece:start])
|
|
60
|
+
result_pieces.append(idx)
|
|
61
|
+
idx += 1
|
|
62
|
+
fmt = format_string[start:end]
|
|
63
|
+
if fmt == "%s":
|
|
64
|
+
arg = SimTypePointer(SimTypeChar())
|
|
65
|
+
elif fmt == "%d":
|
|
66
|
+
arg = SimTypeInt(signed=True)
|
|
67
|
+
elif fmt == "%u":
|
|
68
|
+
arg = SimTypeInt(signed=False)
|
|
69
|
+
elif fmt == "%c":
|
|
70
|
+
arg = SimTypeChar(signed=True)
|
|
71
|
+
else:
|
|
72
|
+
arg = SimTypeBottom()
|
|
73
|
+
result_types.append(arg)
|
|
74
|
+
result_specs.append(fmt)
|
|
75
|
+
last_piece = end
|
|
76
|
+
if last_piece != len(format_string):
|
|
77
|
+
result_pieces.append(format_string[last_piece:])
|
|
78
|
+
|
|
79
|
+
return result_pieces, result_types, result_specs
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class LibcStdioHandlers(FunctionHandler):
|
|
83
|
+
@FunctionCallDataUnwrapped.decorate
|
|
84
|
+
def handle_impl_printf(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
85
|
+
result, source_atoms = handle_printf(state, data, 0)
|
|
86
|
+
dst_atoms = StdoutAtom("printf")
|
|
87
|
+
data.depends(dst_atoms, source_atoms, value=result)
|
|
88
|
+
|
|
89
|
+
@FunctionCallDataUnwrapped.decorate
|
|
90
|
+
def handle_impl_dprintf(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
91
|
+
result, source_atoms = handle_printf(state, data, 1)
|
|
92
|
+
dst_atoms = StdoutAtom("dprintf")
|
|
93
|
+
data.depends(dst_atoms, source_atoms, value=result)
|
|
94
|
+
|
|
95
|
+
@FunctionCallDataUnwrapped.decorate
|
|
96
|
+
def handle_impl_fprintf(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
97
|
+
result, source_atoms = handle_printf(state, data, 1)
|
|
98
|
+
dst_atoms = StdoutAtom("fprintf")
|
|
99
|
+
data.depends(dst_atoms, source_atoms, value=result)
|
|
100
|
+
|
|
101
|
+
@FunctionCallDataUnwrapped.decorate
|
|
102
|
+
def handle_impl_sprintf(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
103
|
+
result, source_atoms = handle_printf(state, data, 1)
|
|
104
|
+
dst_atoms = state.deref(data.args_atoms[0], size=len(result) // 8 if result is not None else 1)
|
|
105
|
+
data.depends(dst_atoms, source_atoms, value=result)
|
|
106
|
+
|
|
107
|
+
@FunctionCallDataUnwrapped.decorate
|
|
108
|
+
def handle_impl_snprintf(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
109
|
+
result, source_atoms = handle_printf(state, data, 2)
|
|
110
|
+
size = state.get_concrete_value(data.args_atoms[1]) or 2
|
|
111
|
+
dst_atoms = state.deref(data.args_atoms[0], size=size)
|
|
112
|
+
data.depends(dst_atoms, source_atoms, value=result)
|
|
113
|
+
|
|
114
|
+
@FunctionCallDataUnwrapped.decorate
|
|
115
|
+
def handle_impl___sprintf_chk(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
116
|
+
result, source_atoms = handle_printf(state, data, 3)
|
|
117
|
+
dst_atoms = state.deref(data.args_atoms[0], size=len(result) // 8 if result is not None else 1)
|
|
118
|
+
data.depends(dst_atoms, source_atoms, value=result)
|
|
119
|
+
|
|
120
|
+
@FunctionCallDataUnwrapped.decorate
|
|
121
|
+
def handle_impl___snprintf_chk(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
122
|
+
result, source_atoms = handle_printf(state, data, 4)
|
|
123
|
+
size = state.get_concrete_value(data.args_atoms[1]) or 2
|
|
124
|
+
dst_atoms = state.deref(data.args_atoms[0], size=size)
|
|
125
|
+
data.depends(dst_atoms, source_atoms, value=result)
|
|
126
|
+
|
|
127
|
+
@FunctionCallDataUnwrapped.decorate
|
|
128
|
+
def handle_impl_scanf(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
129
|
+
handle_scanf(state, data, 0, {StdinAtom("scanf")})
|
|
130
|
+
|
|
131
|
+
handle_impl___isoc99_scanf = handle_impl_scanf
|
|
132
|
+
|
|
133
|
+
@FunctionCallDataUnwrapped.decorate
|
|
134
|
+
def handle_impl_sscanf(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
135
|
+
handle_scanf(state, data, 1, state.deref(data.args_atoms[0], DerefSize.NULL_TERMINATE))
|
|
136
|
+
|
|
137
|
+
handle_impl___isoc99_sscanf = handle_impl_sscanf
|
|
138
|
+
|
|
139
|
+
@FunctionCallDataUnwrapped.decorate
|
|
140
|
+
def handle_impl_fgets(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
141
|
+
size = state.get_concrete_value(data.args_atoms[1]) or 2
|
|
142
|
+
dst_atom = state.deref(data.args_atoms[0], size)
|
|
143
|
+
input_value = claripy.BVS("weh", 8).concat(claripy.BVV(0, 8))
|
|
144
|
+
data.depends(dst_atom, StdinAtom("fgets"), value=input_value)
|
|
145
|
+
data.depends(data.ret_atoms, data.args_atoms[0])
|
|
146
|
+
|
|
147
|
+
@FunctionCallDataUnwrapped.decorate
|
|
148
|
+
def handle_impl_fgetc(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
149
|
+
data.depends(data.ret_atoms, StdinAtom(data.function.name))
|
|
150
|
+
|
|
151
|
+
handle_impl_getchar = handle_impl_getc = handle_impl_fgetc
|
|
152
|
+
|
|
153
|
+
@FunctionCallDataUnwrapped.decorate
|
|
154
|
+
def handle_impl_fread(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
155
|
+
size = state.get_concrete_value(data.args_atoms[1]) or 1
|
|
156
|
+
nmemb = state.get_concrete_value(data.args_atoms[1]) or 2
|
|
157
|
+
dst_atom = state.deref(data.args_atoms[0], size * nmemb)
|
|
158
|
+
data.depends(dst_atom, StdinAtom("fread"))
|
|
159
|
+
|
|
160
|
+
@FunctionCallDataUnwrapped.decorate
|
|
161
|
+
def handle_impl_fwrite(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
162
|
+
size = state.get_concrete_value(data.args_atoms[1]) or 1
|
|
163
|
+
nmemb = state.get_concrete_value(data.args_atoms[1]) or 2
|
|
164
|
+
src_atom = state.deref(data.args_atoms[0], size * nmemb)
|
|
165
|
+
data.depends(StdoutAtom("fwrite"), src_atom, value=state.get_values(src_atom))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def handle_printf(
|
|
169
|
+
state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped, fmt_idx: int
|
|
170
|
+
) -> tuple[MultiValues | None, Iterable[Atom]]:
|
|
171
|
+
format_str = state.get_concrete_value(
|
|
172
|
+
state.deref(data.args_atoms[fmt_idx], DerefSize.NULL_TERMINATE), cast_to=bytes
|
|
173
|
+
)
|
|
174
|
+
if format_str is None:
|
|
175
|
+
_l.info("Hmmm.... non-constant format string")
|
|
176
|
+
return None, set()
|
|
177
|
+
|
|
178
|
+
format_str = format_str.strip(b"\0").decode()
|
|
179
|
+
arg_pieces, arg_types, formats = parse_format_string(format_str)
|
|
180
|
+
data.reset_prototype(SimTypeFunction(data.prototype.args + tuple(arg_types), data.prototype.returnty), state)
|
|
181
|
+
|
|
182
|
+
result = MultiValues(claripy.BVV(b""))
|
|
183
|
+
source_atoms: set[Atom] = set()
|
|
184
|
+
for piece in arg_pieces:
|
|
185
|
+
if isinstance(piece, str):
|
|
186
|
+
if result is not None:
|
|
187
|
+
result = result.concat(piece.encode())
|
|
188
|
+
continue
|
|
189
|
+
atom = data.args_atoms[fmt_idx + 1 + piece]
|
|
190
|
+
fmt = formats[piece]
|
|
191
|
+
|
|
192
|
+
if fmt == "%s":
|
|
193
|
+
buf_atoms = state.deref(atom, DerefSize.NULL_TERMINATE)
|
|
194
|
+
buf_data = state.get_values(buf_atoms)
|
|
195
|
+
if buf_data is not None:
|
|
196
|
+
buf_data = buf_data.extract(0, len(buf_data) // 8 - 1, archinfo.Endness.BE)
|
|
197
|
+
elif fmt == "%u":
|
|
198
|
+
buf_atoms = atom
|
|
199
|
+
buf_data = state.get_concrete_value(buf_atoms)
|
|
200
|
+
if buf_data is not None:
|
|
201
|
+
buf_data = str(buf_data).encode()
|
|
202
|
+
elif fmt == "%d":
|
|
203
|
+
buf_atoms = atom
|
|
204
|
+
buf_data = state.get_concrete_value(buf_atoms)
|
|
205
|
+
if buf_data is not None:
|
|
206
|
+
if buf_data >= 2**31:
|
|
207
|
+
buf_data -= 2**32
|
|
208
|
+
buf_data = str(buf_data).encode()
|
|
209
|
+
elif fmt == "%c":
|
|
210
|
+
buf_atoms = atom
|
|
211
|
+
buf_data = state.get_concrete_value(atom)
|
|
212
|
+
if buf_data is not None:
|
|
213
|
+
buf_data = chr(buf_data).encode()
|
|
214
|
+
else:
|
|
215
|
+
_l.warning("Unimplemented printf format string %s", fmt)
|
|
216
|
+
buf_atoms = set()
|
|
217
|
+
buf_data = None
|
|
218
|
+
if result is not None:
|
|
219
|
+
if buf_data is not None:
|
|
220
|
+
result = result.concat(buf_data)
|
|
221
|
+
source_atoms.update(buf_atoms)
|
|
222
|
+
if result is not None:
|
|
223
|
+
result = result.concat(b"\0")
|
|
224
|
+
|
|
225
|
+
return result, source_atoms
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def handle_scanf(
|
|
229
|
+
state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped, fmt_idx: int, source_atoms: Iterable[Atom]
|
|
230
|
+
):
|
|
231
|
+
format_str = state.get_concrete_value(
|
|
232
|
+
state.deref(data.args_atoms[fmt_idx], DerefSize.NULL_TERMINATE), cast_to=bytes
|
|
233
|
+
)
|
|
234
|
+
if format_str is None:
|
|
235
|
+
_l.info("Hmmm.... non-constant format string")
|
|
236
|
+
return
|
|
237
|
+
format_str = format_str.strip(b"\0").decode()
|
|
238
|
+
arg_pieces, arg_types, formats = parse_format_string(format_str)
|
|
239
|
+
data.reset_prototype(SimTypeFunction(data.prototype.args + tuple(arg_types), data.prototype.returnty), state)
|
|
240
|
+
|
|
241
|
+
for piece in arg_pieces:
|
|
242
|
+
if isinstance(piece, str):
|
|
243
|
+
continue
|
|
244
|
+
atom = data.args_atoms[fmt_idx + 1 + piece]
|
|
245
|
+
fmt = formats[piece]
|
|
246
|
+
buf_data = None
|
|
247
|
+
|
|
248
|
+
if fmt == "%s":
|
|
249
|
+
buf_atom = state.deref(atom, 1)
|
|
250
|
+
buf_data = b"\0"
|
|
251
|
+
elif fmt == "%u":
|
|
252
|
+
buf_atom = state.deref(atom, 4, state.arch.memory_endness)
|
|
253
|
+
elif fmt == "%d":
|
|
254
|
+
buf_atom = state.deref(atom, 4, state.arch.memory_endness)
|
|
255
|
+
elif fmt == "%c":
|
|
256
|
+
buf_atom = state.deref(atom, 1, state.arch.memory_endness)
|
|
257
|
+
else:
|
|
258
|
+
_l.warning("Unimplemented scanf format string %s", fmt)
|
|
259
|
+
continue
|
|
260
|
+
data.depends(buf_atom, source_atoms, value=buf_data)
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
import random
|
|
4
|
+
|
|
5
|
+
import claripy
|
|
6
|
+
|
|
7
|
+
from angr.analyses.reaching_definitions.function_handler import FunctionCallDataUnwrapped, FunctionHandler
|
|
8
|
+
from angr.knowledge_plugins.key_definitions.atoms import Atom
|
|
9
|
+
from angr.knowledge_plugins.key_definitions.live_definitions import DerefSize
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from angr.analyses.reaching_definitions.rd_state import ReachingDefinitionsState
|
|
14
|
+
|
|
15
|
+
# pylint: disable=no-self-use,missing-class-docstring,unused-argument
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class EnvironAtom(Atom):
|
|
19
|
+
def __init__(self, name: str | None):
|
|
20
|
+
self.name = name
|
|
21
|
+
super().__init__(1)
|
|
22
|
+
|
|
23
|
+
def _identity(self):
|
|
24
|
+
if self.name is not None:
|
|
25
|
+
return (self.name,)
|
|
26
|
+
else:
|
|
27
|
+
return ()
|
|
28
|
+
|
|
29
|
+
def __repr__(self):
|
|
30
|
+
return f'<EnvironAtom {self.name if self.name is not None else "(dynamic)"}>'
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class SystemAtom(Atom):
|
|
34
|
+
def __init__(self):
|
|
35
|
+
self.nonce = random.randint(0, 999999999999)
|
|
36
|
+
super().__init__(1)
|
|
37
|
+
|
|
38
|
+
def _identity(self):
|
|
39
|
+
return (self.nonce,)
|
|
40
|
+
|
|
41
|
+
def __repr__(self):
|
|
42
|
+
return "<SystemAtom>"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ExecveAtom(Atom):
|
|
46
|
+
def __init__(self, nonce: int, idx: int, size: int):
|
|
47
|
+
self.nonce = nonce
|
|
48
|
+
self.idx = idx
|
|
49
|
+
super().__init__(size)
|
|
50
|
+
|
|
51
|
+
def _identity(self):
|
|
52
|
+
return (self.nonce,)
|
|
53
|
+
|
|
54
|
+
def __repr__(self):
|
|
55
|
+
return f"<ExecveAtom {self.idx}>"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class LibcStdlibHandlers(FunctionHandler):
|
|
59
|
+
@FunctionCallDataUnwrapped.decorate
|
|
60
|
+
def handle_impl_atoi(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
61
|
+
buf_atoms = state.deref(data.args_atoms[0], DerefSize.NULL_TERMINATE)
|
|
62
|
+
buf_value = state.get_concrete_value(buf_atoms, cast_to=bytes)
|
|
63
|
+
if buf_value is not None:
|
|
64
|
+
buf_value = int(buf_value.decode().strip("\0"))
|
|
65
|
+
data.depends(data.ret_atoms, buf_atoms, value=buf_value)
|
|
66
|
+
|
|
67
|
+
@FunctionCallDataUnwrapped.decorate
|
|
68
|
+
def handle_impl_malloc(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
69
|
+
malloc_size = state.get_concrete_value(data.args_atoms[0]) or 48
|
|
70
|
+
heap_ptr = state.heap_allocator.allocate(malloc_size)
|
|
71
|
+
data.depends(data.ret_atoms, value=state.heap_address(heap_ptr))
|
|
72
|
+
|
|
73
|
+
@FunctionCallDataUnwrapped.decorate
|
|
74
|
+
def handle_impl_calloc(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
75
|
+
nmemb = state.get_concrete_value(data.args_atoms[0]) or 48
|
|
76
|
+
size = state.get_concrete_value(data.args_atoms[0]) or 1
|
|
77
|
+
heap_ptr = state.heap_address(state.heap_allocator.allocate(nmemb * size))
|
|
78
|
+
data.depends(state.deref(heap_ptr, nmemb * size), value=0)
|
|
79
|
+
data.depends(data.ret_atoms, value=heap_ptr)
|
|
80
|
+
|
|
81
|
+
@FunctionCallDataUnwrapped.decorate
|
|
82
|
+
def handle_impl_getenv(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
83
|
+
name_atom = state.deref(data.args_atoms[0], DerefSize.NULL_TERMINATE)
|
|
84
|
+
name_value = state.get_concrete_value(name_atom, cast_to=bytes)
|
|
85
|
+
if name_value is not None:
|
|
86
|
+
name_value = name_value.strip(b"\0").decode()
|
|
87
|
+
data.depends(None, name_atom)
|
|
88
|
+
|
|
89
|
+
# store a buffer, registering it as an output of this function
|
|
90
|
+
# we store this two-byte mixed value because we don't want the value to be picked up by get_concrete_value()
|
|
91
|
+
# but also it should be able to be picked up by NULL_TERMINATE reads
|
|
92
|
+
heap_ptr = state.heap_allocator.allocate(2)
|
|
93
|
+
heap_atom = state.deref(heap_ptr, 2)
|
|
94
|
+
heap_value = claripy.BVS("weh", 8).concat(claripy.BVV(0, 8))
|
|
95
|
+
data.depends(heap_atom, EnvironAtom(name_value), value=heap_value)
|
|
96
|
+
data.depends(data.ret_atoms, value=state.heap_address(heap_ptr))
|
|
97
|
+
|
|
98
|
+
@FunctionCallDataUnwrapped.decorate
|
|
99
|
+
def handle_impl_setenv(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
100
|
+
name_atom = state.deref(data.args_atoms[0], DerefSize.NULL_TERMINATE)
|
|
101
|
+
name_value = state.get_concrete_value(name_atom, cast_to=bytes)
|
|
102
|
+
if name_value is not None:
|
|
103
|
+
name_value = name_value.strip(b"\0").decode()
|
|
104
|
+
data.depends(None, name_atom)
|
|
105
|
+
|
|
106
|
+
src_atom = state.deref(data.args_atoms[1], DerefSize.NULL_TERMINATE)
|
|
107
|
+
src_value = state.get_values(src_atom)
|
|
108
|
+
data.depends(EnvironAtom(name_value), src_atom, value=src_value)
|
|
109
|
+
|
|
110
|
+
@FunctionCallDataUnwrapped.decorate
|
|
111
|
+
def handle_impl_system(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
112
|
+
buf_atom = state.deref(data.args_atoms[0], DerefSize.NULL_TERMINATE)
|
|
113
|
+
data.depends(SystemAtom(), buf_atom)
|
|
114
|
+
|
|
115
|
+
handle_impl_popen = handle_impl_execl = handle_impl_system
|
|
116
|
+
|
|
117
|
+
@FunctionCallDataUnwrapped.decorate
|
|
118
|
+
def handle_impl_execve(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
119
|
+
argv_value = state.get_one_value(data.args_atoms[1])
|
|
120
|
+
if argv_value is None:
|
|
121
|
+
return
|
|
122
|
+
|
|
123
|
+
nonce = random.randint(1, 999999999)
|
|
124
|
+
|
|
125
|
+
# Iterate through each pointer in the array to collect argument strings
|
|
126
|
+
idx = 0
|
|
127
|
+
while True:
|
|
128
|
+
# Read the concrete string pointer value
|
|
129
|
+
argv_deref_atom = state.deref(argv_value, state.arch.bytes, state.arch.memory_endness)
|
|
130
|
+
if argv_deref_atom is None:
|
|
131
|
+
# unknown if array continues
|
|
132
|
+
break
|
|
133
|
+
|
|
134
|
+
argv_deref_concrete = state.get_concrete_value(argv_deref_atom)
|
|
135
|
+
if argv_deref_concrete is None:
|
|
136
|
+
# unknown if array continues
|
|
137
|
+
break
|
|
138
|
+
|
|
139
|
+
if argv_deref_concrete == 0:
|
|
140
|
+
# End of array
|
|
141
|
+
break
|
|
142
|
+
|
|
143
|
+
string_atom = state.deref(argv_deref_concrete, DerefSize.NULL_TERMINATE)
|
|
144
|
+
string_val = None if string_atom is None else state.get_values(string_atom)
|
|
145
|
+
|
|
146
|
+
atom = ExecveAtom(nonce, idx, len(string_val) // 8 if string_val is not None else 1)
|
|
147
|
+
data.depends(atom, [] if string_atom is None else [string_atom], value=string_val)
|
|
148
|
+
|
|
149
|
+
# Increment by size of pointer for this arch
|
|
150
|
+
argv_value += state.arch.bytes
|
|
151
|
+
idx += 1
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import archinfo
|
|
2
|
+
from angr.analyses.reaching_definitions.function_handler import FunctionCallDataUnwrapped, FunctionHandler
|
|
3
|
+
from angr.analyses.reaching_definitions.rd_state import ReachingDefinitionsState
|
|
4
|
+
from angr.knowledge_plugins.key_definitions.live_definitions import DerefSize
|
|
5
|
+
|
|
6
|
+
# pylint: disable=no-self-use,missing-class-docstring,unused-argument
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class LibcUnistdHandlers(FunctionHandler):
|
|
10
|
+
@FunctionCallDataUnwrapped.decorate
|
|
11
|
+
def handle_impl_strcat(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
12
|
+
src0_atom = state.deref(data.args_atoms[0], DerefSize.NULL_TERMINATE)
|
|
13
|
+
src1_atom = state.deref(data.args_atoms[1], DerefSize.NULL_TERMINATE)
|
|
14
|
+
src0_value = state.get_values(src0_atom)
|
|
15
|
+
src1_value = state.get_values(src1_atom)
|
|
16
|
+
if src0_value is not None and src1_value is not None:
|
|
17
|
+
src0_value = src0_value.extract(0, len(src0_value) // 8 - 1, archinfo.Endness.BE)
|
|
18
|
+
dest_value = src0_value.concat(src1_value)
|
|
19
|
+
dest_atom = state.deref(data.args_atoms[0], len(dest_value) // 8, endness=archinfo.Endness.BE)
|
|
20
|
+
else:
|
|
21
|
+
dest_value = None
|
|
22
|
+
dest_atom = src0_atom
|
|
23
|
+
data.depends(dest_atom, src0_atom, src1_atom, value=dest_value)
|
|
24
|
+
data.depends(data.ret_atoms, data.args_atoms[0], value=src0_value)
|
|
25
|
+
|
|
26
|
+
handle_impl_strncat = handle_impl_strcat
|
|
27
|
+
|
|
28
|
+
@FunctionCallDataUnwrapped.decorate
|
|
29
|
+
def handle_impl_strlen(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
30
|
+
src_atom = state.deref(data.args_atoms[0], DerefSize.NULL_TERMINATE)
|
|
31
|
+
src_str = state.get_values(src_atom)
|
|
32
|
+
if src_str is not None:
|
|
33
|
+
data.depends(data.ret_atoms, src_atom, value=len(src_str) // 8 - 1)
|
|
34
|
+
else:
|
|
35
|
+
data.depends(data.ret_atoms, src_atom)
|
|
36
|
+
|
|
37
|
+
@FunctionCallDataUnwrapped.decorate
|
|
38
|
+
def handle_impl_strcpy(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
39
|
+
src_atom = state.deref(data.args_atoms[1], DerefSize.NULL_TERMINATE)
|
|
40
|
+
src_str = state.get_values(src_atom)
|
|
41
|
+
if src_str is not None:
|
|
42
|
+
dst_atom = state.deref(data.args_atoms[0], len(src_str) // 8)
|
|
43
|
+
data.depends(dst_atom, src_atom, value=src_str)
|
|
44
|
+
data.depends(data.ret_atoms, data.args_atoms[0], value=state.get_values(data.args_atoms[0]))
|
|
45
|
+
|
|
46
|
+
@FunctionCallDataUnwrapped.decorate
|
|
47
|
+
def handle_impl_strncpy(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
48
|
+
n = state.get_concrete_value(data.args_atoms[1])
|
|
49
|
+
src_atom = state.deref(data.args_atoms[2], DerefSize.NULL_TERMINATE if n is None else n)
|
|
50
|
+
src_str = state.get_values(src_atom)
|
|
51
|
+
if src_str is not None:
|
|
52
|
+
dst_atom = state.deref(data.args_atoms[0], len(src_str) // 8)
|
|
53
|
+
data.depends(dst_atom, src_atom, value=src_str)
|
|
54
|
+
data.depends(data.ret_atoms, data.args_atoms[0], value=state.get_values(data.args_atoms[0]))
|
|
55
|
+
|
|
56
|
+
@FunctionCallDataUnwrapped.decorate
|
|
57
|
+
def handle_impl_strdup(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
58
|
+
src_atom = state.deref(data.args_atoms[1], DerefSize.NULL_TERMINATE)
|
|
59
|
+
src_str = state.get_values(src_atom)
|
|
60
|
+
if src_str is not None:
|
|
61
|
+
malloc_size = len(src_str) // 8
|
|
62
|
+
else:
|
|
63
|
+
malloc_size = 1
|
|
64
|
+
heap_ptr = state.heap_allocator.allocate(malloc_size)
|
|
65
|
+
dst_atom = state.deref(heap_ptr, malloc_size)
|
|
66
|
+
data.depends(dst_atom, src_atom, value=src_str)
|
|
67
|
+
data.depends(data.ret_atoms, data.args_atoms[0], value=state.get_values(data.args_atoms[0]))
|
|
68
|
+
|
|
69
|
+
@FunctionCallDataUnwrapped.decorate
|
|
70
|
+
def handle_impl_memcpy(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
71
|
+
size = state.get_concrete_value(data.args_atoms[2])
|
|
72
|
+
if size is not None:
|
|
73
|
+
src_atom = state.deref(data.args_atoms[1], size)
|
|
74
|
+
dst_atom = state.deref(data.args_atoms[0], size)
|
|
75
|
+
data.depends(dst_atom, src_atom, value=state.get_values(src_atom))
|
|
76
|
+
data.depends(data.ret_atoms, data.args_atoms[0], value=state.get_values(data.args_atoms[0]))
|
|
77
|
+
|
|
78
|
+
@FunctionCallDataUnwrapped.decorate
|
|
79
|
+
def handle_impl_memset(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
80
|
+
size = state.get_concrete_value(data.args_atoms[2])
|
|
81
|
+
if size is not None:
|
|
82
|
+
dst_atom = state.deref(data.args_atoms[0], size)
|
|
83
|
+
data.depends(dst_atom, data.args_atoms[1])
|
|
84
|
+
data.depends(data.ret_atoms, data.args_atoms[0], value=state.get_values(data.args_atoms[0]))
|
|
85
|
+
|
|
86
|
+
@FunctionCallDataUnwrapped.decorate
|
|
87
|
+
def handle_impl_strtok(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
88
|
+
# stub: just return the haystack pointer
|
|
89
|
+
data.depends(data.ret_atoms, data.args_atoms[0], value=state.get_values(data.args_atoms[0]))
|
|
90
|
+
|
|
91
|
+
handle_impl_strtok_r = handle_impl_strstr = handle_impl_strcasestr = handle_impl_strchr = handle_imple_strrchr = (
|
|
92
|
+
handle_impl_strchrnul
|
|
93
|
+
) = handle_impl_strtok
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from angr.analyses.reaching_definitions.function_handler import FunctionCallDataUnwrapped, FunctionHandler
|
|
2
|
+
from angr.analyses.reaching_definitions.function_handler_library.stdio import StdinAtom, StdoutAtom
|
|
3
|
+
from angr.analyses.reaching_definitions.rd_state import ReachingDefinitionsState
|
|
4
|
+
|
|
5
|
+
# pylint: disable=no-self-use,missing-class-docstring,unused-argument
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LibcUnistdHandlers(FunctionHandler):
|
|
9
|
+
@FunctionCallDataUnwrapped.decorate
|
|
10
|
+
def handle_impl_read(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
11
|
+
size = state.get_concrete_value(data.args_atoms[2]) or 1
|
|
12
|
+
dst_atom = state.deref(data.args_atoms[1], size)
|
|
13
|
+
data.depends(dst_atom, StdinAtom(data.function.name))
|
|
14
|
+
|
|
15
|
+
handle_impl_recv = handle_impl_recvfrom = handle_impl_read
|
|
16
|
+
|
|
17
|
+
@FunctionCallDataUnwrapped.decorate
|
|
18
|
+
def handle_impl_write(self, state: ReachingDefinitionsState, data: FunctionCallDataUnwrapped):
|
|
19
|
+
size = state.get_concrete_value(data.args_atoms[2]) or 1
|
|
20
|
+
src_atom = state.deref(data.args_atoms[1], size)
|
|
21
|
+
data.depends(StdoutAtom(data.function.name), src_atom, value=state.get_values(src_atom))
|
|
22
|
+
|
|
23
|
+
handle_impl_send = handle_impl_write
|
|
@@ -504,7 +504,9 @@ class ReachingDefinitionsState:
|
|
|
504
504
|
def get_values(self, spec: Atom | Definition | Iterable[Atom]) -> MultiValues | None:
|
|
505
505
|
return self.live_definitions.get_values(spec)
|
|
506
506
|
|
|
507
|
-
def get_one_value(
|
|
507
|
+
def get_one_value(
|
|
508
|
+
self, spec: Atom | Definition | Iterable[Atom] | Iterable[Definition], strip_annotations: bool = False
|
|
509
|
+
) -> claripy.ast.bv.BV | None:
|
|
508
510
|
return self.live_definitions.get_one_value(spec, strip_annotations=strip_annotations)
|
|
509
511
|
|
|
510
512
|
@overload
|
angr/analyses/vfg.py
CHANGED
|
@@ -1572,11 +1572,11 @@ class VFG(ForwardAnalysis[SimState, VFGNode, VFGJob, BlockID], Analysis): # pyl
|
|
|
1572
1572
|
# FIXME: Now we are assuming the sp is restored to its original value
|
|
1573
1573
|
reg_sp_expr = successor_state.regs.sp
|
|
1574
1574
|
|
|
1575
|
-
if isinstance(reg_sp_expr
|
|
1576
|
-
reg_sp_si = reg_sp_expr
|
|
1575
|
+
if isinstance(claripy.backends.vsa.convert(reg_sp_expr), claripy.vsa.StridedInterval):
|
|
1576
|
+
reg_sp_si = claripy.backends.vsa.convert(reg_sp_expr)
|
|
1577
1577
|
# reg_sp_si.min # reg_sp_val
|
|
1578
|
-
elif isinstance(reg_sp_expr
|
|
1579
|
-
reg_sp_si = next(iter(reg_sp_expr.
|
|
1578
|
+
elif isinstance(claripy.backends.vsa.convert(reg_sp_expr), claripy.vsa.ValueSet):
|
|
1579
|
+
reg_sp_si = next(iter(claripy.backends.vsa.convert(reg_sp_expr).items()))[1]
|
|
1580
1580
|
# reg_sp_si.min # reg_sp_val
|
|
1581
1581
|
# TODO: Finish it!
|
|
1582
1582
|
|
|
@@ -1717,21 +1717,20 @@ class VFG(ForwardAnalysis[SimState, VFGNode, VFGJob, BlockID], Analysis): # pyl
|
|
|
1717
1717
|
reg_sp_offset = arch.sp_offset
|
|
1718
1718
|
reg_sp_expr = successor_state.registers.load(reg_sp_offset, size=arch.bytes, endness=arch.register_endness)
|
|
1719
1719
|
|
|
1720
|
-
|
|
1720
|
+
reg_sp_expr_vsa = claripy.backends.vsa.convert(reg_sp_expr)
|
|
1721
|
+
if isinstance(reg_sp_expr_vsa, claripy.bv.BVV):
|
|
1721
1722
|
reg_sp_val = successor_state.solver.eval(reg_sp_expr)
|
|
1722
1723
|
reg_sp_si = successor_state.solver.SI(to_conv=reg_sp_expr)
|
|
1723
|
-
reg_sp_si = reg_sp_si
|
|
1724
|
-
elif
|
|
1725
|
-
reg_sp_val = reg_sp_expr
|
|
1724
|
+
reg_sp_si = claripy.backends.vsa.convert(reg_sp_si)
|
|
1725
|
+
elif isinstance(reg_sp_expr_vsa, int):
|
|
1726
|
+
reg_sp_val = claripy.backends.vsa.convert(reg_sp_expr)
|
|
1726
1727
|
reg_sp_si = successor_state.solver.SI(bits=successor_state.arch.bits, to_conv=reg_sp_val)
|
|
1727
|
-
reg_sp_si = reg_sp_si
|
|
1728
|
-
elif (
|
|
1729
|
-
|
|
1730
|
-
): # pylint:disable=unidiomatic-typecheck # type: ignore
|
|
1731
|
-
reg_sp_si = reg_sp_expr._model_vsa
|
|
1728
|
+
reg_sp_si = claripy.backends.vsa.convert(reg_sp_si)
|
|
1729
|
+
elif isinstance(reg_sp_expr_vsa, claripy.vsa.StridedInterval):
|
|
1730
|
+
reg_sp_si = reg_sp_expr_vsa
|
|
1732
1731
|
reg_sp_val = reg_sp_si.min
|
|
1733
1732
|
else:
|
|
1734
|
-
reg_sp_si = next(iter(
|
|
1733
|
+
reg_sp_si = next(iter(reg_sp_expr_vsa.items()))[1]
|
|
1735
1734
|
reg_sp_val = reg_sp_si.min
|
|
1736
1735
|
|
|
1737
1736
|
reg_sp_val = reg_sp_val - arch.bytes # TODO: Is it OK?
|
angr/code_location.py
CHANGED
|
@@ -20,12 +20,12 @@ class CodeLocation:
|
|
|
20
20
|
|
|
21
21
|
def __init__(
|
|
22
22
|
self,
|
|
23
|
-
block_addr: int,
|
|
23
|
+
block_addr: int | None,
|
|
24
24
|
stmt_idx: int | None,
|
|
25
25
|
sim_procedure=None,
|
|
26
26
|
ins_addr: int | None = None,
|
|
27
27
|
context: Any = None,
|
|
28
|
-
block_idx: int = None,
|
|
28
|
+
block_idx: int | None = None,
|
|
29
29
|
**kwargs,
|
|
30
30
|
):
|
|
31
31
|
"""
|
|
@@ -41,12 +41,12 @@ class CodeLocation:
|
|
|
41
41
|
:param kwargs: Optional arguments, will be stored, but not used in __eq__ or __hash__.
|
|
42
42
|
"""
|
|
43
43
|
|
|
44
|
-
self.block_addr: int = block_addr
|
|
44
|
+
self.block_addr: int | None = block_addr
|
|
45
45
|
self.stmt_idx: int | None = stmt_idx
|
|
46
46
|
self.sim_procedure = sim_procedure
|
|
47
47
|
self.ins_addr: int | None = ins_addr
|
|
48
48
|
self.context: tuple[int] | None = context
|
|
49
|
-
self.block_idx = block_idx
|
|
49
|
+
self.block_idx: int | None = block_idx
|
|
50
50
|
self._hash = None
|
|
51
51
|
|
|
52
52
|
self.info: dict | None = None
|
angr/engines/vex/heavy/heavy.py
CHANGED
|
@@ -349,7 +349,7 @@ class HeavyVEXMixin(SuccessorsMixin, ClaripyDataMixin, SimStateStorageMixin, VEX
|
|
|
349
349
|
def _perform_vex_expr_Load(self, addr, ty, endness, **kwargs):
|
|
350
350
|
result = super()._perform_vex_expr_Load(addr, ty, endness, **kwargs)
|
|
351
351
|
if o.UNINITIALIZED_ACCESS_AWARENESS in self.state.options:
|
|
352
|
-
if getattr(addr
|
|
352
|
+
if getattr(claripy.backends.vsa.convert(addr), "uninitialized", False):
|
|
353
353
|
raise errors.SimUninitializedAccessError("addr", addr)
|
|
354
354
|
return result
|
|
355
355
|
|