angr 9.2.114__py3-none-macosx_11_0_arm64.whl → 9.2.115__py3-none-macosx_11_0_arm64.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.

Files changed (41) hide show
  1. angr/__init__.py +1 -1
  2. angr/__main__.py +2 -2
  3. angr/analyses/cfg/cfg_fast.py +1 -1
  4. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +2 -2
  5. angr/analyses/decompiler/decompilation_options.py +2 -12
  6. angr/analyses/decompiler/decompiler.py +14 -3
  7. angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +3 -0
  8. angr/analyses/decompiler/optimization_passes/cross_jump_reverter.py +0 -3
  9. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +2 -3
  10. angr/analyses/decompiler/optimization_passes/optimization_pass.py +9 -2
  11. angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +2 -0
  12. angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +2 -0
  13. angr/analyses/decompiler/structuring/__init__.py +6 -2
  14. angr/analyses/decompiler/structuring/phoenix.py +28 -91
  15. angr/analyses/decompiler/structuring/recursive_structurer.py +0 -3
  16. angr/analyses/decompiler/structuring/sailr.py +111 -0
  17. angr/analyses/decompiler/structuring/structurer_base.py +0 -2
  18. angr/analyses/reaching_definitions/function_handler.py +11 -1
  19. angr/analyses/reaching_definitions/function_handler_library/__init__.py +0 -0
  20. angr/analyses/reaching_definitions/function_handler_library/stdio.py +260 -0
  21. angr/analyses/reaching_definitions/function_handler_library/stdlib.py +151 -0
  22. angr/analyses/reaching_definitions/function_handler_library/string.py +93 -0
  23. angr/analyses/reaching_definitions/function_handler_library/unistd.py +23 -0
  24. angr/analyses/reaching_definitions/rd_state.py +3 -1
  25. angr/analyses/vfg.py +13 -14
  26. angr/code_location.py +4 -4
  27. angr/engines/vex/heavy/heavy.py +1 -1
  28. angr/lib/angr_native.dylib +0 -0
  29. angr/procedures/libc/strlen.py +5 -2
  30. angr/sim_variable.py +3 -18
  31. angr/state_plugins/solver.py +3 -9
  32. angr/storage/memory_mixins/address_concretization_mixin.py +1 -1
  33. angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
  34. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +5 -5
  35. angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +3 -3
  36. {angr-9.2.114.dist-info → angr-9.2.115.dist-info}/METADATA +6 -6
  37. {angr-9.2.114.dist-info → angr-9.2.115.dist-info}/RECORD +41 -35
  38. {angr-9.2.114.dist-info → angr-9.2.115.dist-info}/WHEEL +1 -1
  39. {angr-9.2.114.dist-info → angr-9.2.115.dist-info}/LICENSE +0 -0
  40. {angr-9.2.114.dist-info → angr-9.2.115.dist-info}/entry_points.txt +0 -0
  41. {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.
@@ -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(self, spec: Atom | Definition, strip_annotations: bool = False) -> claripy.ast.bv.BV | None:
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._model_vsa, claripy.vsa.StridedInterval): # type: ignore
1576
- reg_sp_si = reg_sp_expr._model_vsa
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._model_vsa, claripy.vsa.ValueSet): # type: ignore
1579
- reg_sp_si = next(iter(reg_sp_expr._model_vsa.items()))[1] # type: ignore
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
- if type(reg_sp_expr._model_vsa) is claripy.BVV: # pylint:disable=unidiomatic-typecheck
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._model_vsa
1724
- elif type(reg_sp_expr._model_vsa) is int: # pylint:disable=unidiomatic-typecheck
1725
- reg_sp_val = reg_sp_expr._model_vsa
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._model_vsa
1728
- elif (
1729
- type(reg_sp_expr._model_vsa) is claripy.vsa.StridedInterval
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(reg_sp_expr._model_vsa.items()))[1]
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
@@ -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._model_vsa, "uninitialized", False):
352
+ if getattr(claripy.backends.vsa.convert(addr), "uninitialized", False):
353
353
  raise errors.SimUninitializedAccessError("addr", addr)
354
354
  return result
355
355
 
Binary file