angr 9.2.65__py3-none-win_amd64.whl → 9.2.66__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of angr might be problematic. Click here for more details.

Files changed (45) hide show
  1. angr/__init__.py +55 -2
  2. angr/analyses/calling_convention.py +4 -3
  3. angr/analyses/cfg/cfg_base.py +2 -2
  4. angr/analyses/cfg/cfg_fast.py +128 -60
  5. angr/analyses/decompiler/ail_simplifier.py +1 -2
  6. angr/analyses/decompiler/block_simplifier.py +4 -3
  7. angr/analyses/decompiler/callsite_maker.py +1 -1
  8. angr/analyses/decompiler/condition_processor.py +5 -3
  9. angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +51 -8
  10. angr/analyses/decompiler/peephole_optimizations/__init__.py +1 -1
  11. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +92 -0
  12. angr/analyses/decompiler/structured_codegen/c.py +59 -6
  13. angr/analyses/decompiler/utils.py +1 -1
  14. angr/analyses/find_objects_static.py +4 -4
  15. angr/analyses/propagator/engine_ail.py +2 -1
  16. angr/analyses/reaching_definitions/__init__.py +1 -3
  17. angr/analyses/reaching_definitions/dep_graph.py +33 -4
  18. angr/analyses/reaching_definitions/engine_ail.py +5 -6
  19. angr/analyses/reaching_definitions/engine_vex.py +6 -7
  20. angr/analyses/reaching_definitions/external_codeloc.py +0 -27
  21. angr/analyses/reaching_definitions/function_handler.py +145 -23
  22. angr/analyses/reaching_definitions/rd_initializer.py +221 -0
  23. angr/analyses/reaching_definitions/rd_state.py +95 -153
  24. angr/analyses/reaching_definitions/reaching_definitions.py +15 -3
  25. angr/calling_conventions.py +2 -2
  26. angr/code_location.py +24 -0
  27. angr/exploration_techniques/__init__.py +28 -0
  28. angr/knowledge_plugins/cfg/cfg_model.py +1 -1
  29. angr/knowledge_plugins/key_definitions/__init__.py +12 -1
  30. angr/knowledge_plugins/key_definitions/atoms.py +9 -0
  31. angr/knowledge_plugins/key_definitions/definition.py +13 -18
  32. angr/knowledge_plugins/key_definitions/live_definitions.py +350 -106
  33. angr/lib/angr_native.dll +0 -0
  34. angr/project.py +1 -1
  35. angr/sim_manager.py +15 -0
  36. angr/sim_state.py +3 -3
  37. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +56 -8
  38. angr/storage/memory_object.py +3 -1
  39. angr/utils/typing.py +16 -0
  40. {angr-9.2.65.dist-info → angr-9.2.66.dist-info}/METADATA +7 -7
  41. {angr-9.2.65.dist-info → angr-9.2.66.dist-info}/RECORD +44 -42
  42. angr/analyses/decompiler/peephole_optimizations/conv_const_mull_a_shift.py +0 -75
  43. {angr-9.2.65.dist-info → angr-9.2.66.dist-info}/LICENSE +0 -0
  44. {angr-9.2.65.dist-info → angr-9.2.66.dist-info}/WHEEL +0 -0
  45. {angr-9.2.65.dist-info → angr-9.2.66.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,221 @@
1
+ import logging
2
+ from typing import Optional, Tuple, TYPE_CHECKING
3
+
4
+ import claripy
5
+ from archinfo import Arch
6
+ from angr.sim_type import SimType, SimTypeFunction
7
+ from angr.analyses.reaching_definitions.subject import Subject
8
+ from angr.analyses.reaching_definitions.call_trace import CallTrace
9
+ from angr.calling_conventions import SimRegArg, SimStackArg, SimCC, SimFunctionArgument
10
+ from angr.engines.light import SpOffset
11
+ from angr.knowledge_plugins import Function
12
+ from angr.knowledge_plugins.key_definitions.atoms import Register, MemoryLocation
13
+ from angr.knowledge_plugins.key_definitions.definition import Definition
14
+ from angr.knowledge_plugins.key_definitions.tag import ParameterTag, InitialValueTag
15
+ from angr.code_location import ExternalCodeLocation
16
+
17
+ l = logging.getLogger(name=__name__)
18
+
19
+ if TYPE_CHECKING:
20
+ from angr.analyses.reaching_definitions.rd_state import ReachingDefinitionsState
21
+
22
+
23
+ class RDAStateInitializer:
24
+ """
25
+ This class acts as the basic implementation for the logic that initializes the base state
26
+ for the reaching definitions analysis.
27
+
28
+ It also defines the _interface_ that a state initializer should implement,
29
+ if the language/runtime being analyzed requires more complicated logic to set up the state.
30
+
31
+ This code/logic was previously part of the ReachingDefinitionsState class, but this was moved here to separate
32
+ these two concerns, and allow easily changing the initialization logic without having to change the state class.
33
+
34
+ """
35
+
36
+ def __init__(self, arch: Arch):
37
+ self.arch: Arch = arch
38
+
39
+ def initialize_function_state(
40
+ self, state: "ReachingDefinitionsState", cc: Optional[SimCC], func_addr: int, rtoc_value: Optional[int] = None
41
+ ) -> None:
42
+ """
43
+ This is the entry point to the state initialization logic.
44
+ It will be called during the initialization of an ReachingDefinitionsState,
45
+ if the state was freshly created (without existing live_definitions)
46
+ """
47
+ call_string = self._generate_call_string(state._subject, func_addr)
48
+ ex_loc = ExternalCodeLocation(call_string)
49
+ if state.analysis is not None:
50
+ state.analysis.model.at_new_stmt(ex_loc)
51
+
52
+ # Setup Stack pointer
53
+ self.initialize_stack_pointer(state, func_addr, ex_loc)
54
+
55
+ # initialize function arguments, based on the calling convention and signature
56
+ if state.analysis is not None and cc is not None:
57
+ prototype = state.analysis.kb.functions[func_addr].prototype
58
+ else:
59
+ prototype = None
60
+ self.initialize_all_function_arguments(state, func_addr, ex_loc, cc, prototype)
61
+
62
+ # architecture dependent initialization
63
+ self.initialize_architectural_state(state, func_addr, ex_loc, rtoc_value)
64
+
65
+ if state.analysis is not None:
66
+ state.analysis.model.complete_loc()
67
+
68
+ def initialize_all_function_arguments(
69
+ self,
70
+ state: "ReachingDefinitionsState",
71
+ func_addr: int,
72
+ ex_loc: ExternalCodeLocation,
73
+ cc: Optional[SimCC],
74
+ prototype: Optional[SimTypeFunction],
75
+ ) -> None:
76
+ """
77
+ This method handles the setup for _all_ arguments of a function.
78
+
79
+ The default implementation uses the calling convention to extract the argument locations, associates them with
80
+ the type, and passes them to the logic for one argument.
81
+
82
+ You probably don't need to override this
83
+ """
84
+ if cc is not None and prototype is not None:
85
+ # Type inference for zip is broken in PyCharm 2023.* currently, so we help out manually
86
+ loc: SimFunctionArgument
87
+ ty: SimType
88
+ for loc, ty in zip(cc.arg_locs(prototype), prototype.args):
89
+ for arg in loc.get_footprint():
90
+ self.initialize_one_function_argument(state, func_addr, ex_loc, arg, ty)
91
+
92
+ def initialize_one_function_argument(
93
+ self,
94
+ state: "ReachingDefinitionsState",
95
+ func_addr: int,
96
+ ex_loc: ExternalCodeLocation,
97
+ argument_location: SimFunctionArgument,
98
+ argument_type: Optional[SimType] = None,
99
+ ) -> None:
100
+ """
101
+ This method handles the setup for _one_ argument of a function.
102
+ This is the main method to override for custom initialization logic.
103
+
104
+ The default implementation initializes only the argument location itself, but the signature allows
105
+ this to support extra logic based on the _type_ of the argument as well.
106
+
107
+ For example if the argument is a pointer to something,
108
+ the default implementation would only set up the register with the value TOP.
109
+
110
+ A custom implementation could instead dedicate some memory somewhere (e.g. on the heap), setup whatever object
111
+ is being pointed to, and then put the actual pointer to this inside the register
112
+ """
113
+ _ = argument_type
114
+ if isinstance(argument_location, SimRegArg):
115
+ self._initialize_function_argument_register(state, func_addr, ex_loc, argument_location)
116
+ elif isinstance(argument_location, SimStackArg):
117
+ self._initialize_function_argument_stack(state, func_addr, ex_loc, argument_location)
118
+ else:
119
+ raise TypeError("Unsupported parameter type %s." % type(argument_location).__name__)
120
+
121
+ def initialize_stack_pointer(
122
+ self, state: "ReachingDefinitionsState", _func_addr: int, ex_loc: ExternalCodeLocation
123
+ ) -> None:
124
+ # initialize stack pointer
125
+ sp_atom = Register(self.arch.sp_offset, self.arch.bytes)
126
+ sp_def = Definition(sp_atom, ex_loc, tags={InitialValueTag()})
127
+ sp = state.annotate_with_def(state._initial_stack_pointer(), sp_def)
128
+ state.registers.store(self.arch.sp_offset, sp)
129
+
130
+ def initialize_architectural_state(
131
+ self,
132
+ state: "ReachingDefinitionsState",
133
+ func_addr: int,
134
+ ex_loc: ExternalCodeLocation,
135
+ rtoc_value: Optional[int] = None,
136
+ ) -> None:
137
+ """
138
+ Some architectures require initialization that is specific to that architecture.
139
+
140
+ Override this if you need to add support for an architecture that requires this, and isn't covered yet
141
+ """
142
+ if self.arch.name.startswith("PPC64"):
143
+ if rtoc_value is None:
144
+ raise TypeError("rtoc_value must be provided on PPC64.")
145
+ offset, size = self.arch.registers["rtoc"]
146
+ rtoc_atom = Register(offset, size)
147
+ rtoc_def = Definition(rtoc_atom, ex_loc, tags={InitialValueTag()})
148
+ state.all_definitions.add(rtoc_def)
149
+ if state.analysis is not None:
150
+ state.analysis.model.add_def(rtoc_def, ex_loc)
151
+ rtoc = state.annotate_with_def(claripy.BVV(rtoc_value, self.arch.bits), rtoc_def)
152
+ state.registers.store(offset, rtoc)
153
+ elif self.arch.name.startswith("MIPS64"):
154
+ offset, size = self.arch.registers["t9"]
155
+ t9_atom = Register(offset, size)
156
+ t9_def = Definition(t9_atom, ex_loc, tags={InitialValueTag()})
157
+ state.all_definitions.add(t9_def)
158
+ if state.analysis is not None:
159
+ state.analysis.model.add_def(t9_def, ex_loc)
160
+ t9 = state.annotate_with_def(claripy.BVV(func_addr, self.arch.bits), t9_def)
161
+ state.registers.store(offset, t9)
162
+ elif self.arch.name.startswith("MIPS"):
163
+ if func_addr is None:
164
+ l.warning("func_addr must not be None to initialize a function in mips")
165
+ t9_offset = self.arch.registers["t9"][0]
166
+ t9_atom = Register(t9_offset, self.arch.bytes)
167
+ t9_def = Definition(t9_atom, ex_loc, tags={InitialValueTag()})
168
+ state.all_definitions.add(t9_def)
169
+ if state.analysis is not None:
170
+ state.analysis.model.add_def(t9_def, ex_loc)
171
+ t9 = state.annotate_with_def(claripy.BVV(func_addr, self.arch.bits), t9_def)
172
+ state.registers.store(t9_offset, t9)
173
+
174
+ def _initialize_function_argument_register(
175
+ self,
176
+ state: "ReachingDefinitionsState",
177
+ func_addr: int,
178
+ ex_loc: ExternalCodeLocation,
179
+ arg: SimRegArg,
180
+ value: Optional[claripy.ast.Base] = None,
181
+ ):
182
+ # FIXME: implement reg_offset handling in SimRegArg
183
+ reg_offset = self.arch.registers[arg.reg_name][0]
184
+ reg_atom = Register(reg_offset, self.arch.bytes)
185
+ reg_def = Definition(reg_atom, ex_loc, tags={ParameterTag(function=func_addr)})
186
+ state.all_definitions.add(reg_def)
187
+ if state.analysis is not None:
188
+ state.analysis.model.add_def(reg_def, ex_loc)
189
+ if value is None:
190
+ value = state.top(self.arch.bits)
191
+ reg = state.annotate_with_def(value, reg_def)
192
+ state.registers.store(reg_offset, reg)
193
+
194
+ def _initialize_function_argument_stack(
195
+ self, state: "ReachingDefinitionsState", func_addr: int, ex_loc: ExternalCodeLocation, arg: SimStackArg
196
+ ):
197
+ ml_atom = MemoryLocation(SpOffset(self.arch.bits, arg.stack_offset), arg.size)
198
+ ml_def = Definition(ml_atom, ex_loc, tags={ParameterTag(function=func_addr)})
199
+ state.all_definitions.add(ml_def)
200
+ if state.analysis is not None:
201
+ state.analysis.model.add_def(ml_def, ex_loc)
202
+ ml = state.annotate_with_def(state.top(self.arch.bits), ml_def)
203
+ stack_address = state.get_stack_address(state.stack_address(arg.stack_offset))
204
+ state.stack.store(stack_address, ml, endness=self.arch.memory_endness)
205
+
206
+ @staticmethod
207
+ def _generate_call_string(subject: Subject, current_address: int) -> Optional[Tuple[int, ...]]:
208
+ if isinstance(subject.content, Function):
209
+ return (subject.content.addr,)
210
+ elif isinstance(subject.content, CallTrace):
211
+ if any(current_address == x.caller_func_addr for x in subject.content.callsites):
212
+ callsites = iter(reversed([x.caller_func_addr for x in subject.content.callsites]))
213
+ for call_addr in callsites:
214
+ if current_address == call_addr:
215
+ break
216
+ return tuple(callsites)
217
+ else:
218
+ return tuple(x.caller_func_addr for x in subject.content.callsites)
219
+ else:
220
+ l.warning("Subject with unknown content-type")
221
+ return None
@@ -1,13 +1,18 @@
1
- from typing import Optional, Iterable, Set, Tuple, Any, TYPE_CHECKING, Iterator, Union
1
+ from typing import Optional, Iterable, Set, Tuple, Any, TYPE_CHECKING, Iterator, Union, overload, Type
2
2
  import logging
3
3
 
4
4
  import archinfo
5
5
  import claripy
6
6
 
7
- from ...analyses.reaching_definitions.call_trace import CallTrace
7
+ from angr.misc.ux import deprecated
8
+ from angr.knowledge_plugins.key_definitions.environment import Environment
9
+ from angr.knowledge_plugins.key_definitions.tag import Tag
10
+ from angr.knowledge_plugins.key_definitions.heap_address import HeapAddress
11
+ from angr.engines.light import SpOffset
12
+ from angr.code_location import CodeLocation
8
13
  from ...storage.memory_mixins.paged_memory.pages.multi_values import MultiValues
9
14
  from ...storage.memory_mixins import MultiValuedMemory
10
- from ...knowledge_plugins.key_definitions import LiveDefinitions
15
+ from ...knowledge_plugins.key_definitions import LiveDefinitions, DerefSize, Definition
11
16
  from ...knowledge_plugins.key_definitions.atoms import (
12
17
  Atom,
13
18
  GuardUse,
@@ -15,17 +20,9 @@ from ...knowledge_plugins.key_definitions.atoms import (
15
20
  MemoryLocation,
16
21
  ConstantSrc,
17
22
  )
18
- from ...knowledge_plugins.functions.function import Function
19
- from ...knowledge_plugins.key_definitions.definition import Definition
20
- from ...knowledge_plugins.key_definitions.environment import Environment
21
- from ...knowledge_plugins.key_definitions.tag import InitialValueTag, ParameterTag, Tag
22
- from ...knowledge_plugins.key_definitions.heap_address import HeapAddress
23
- from ...calling_conventions import SimCC, SimRegArg, SimStackArg
24
- from ...engines.light import SpOffset
25
- from ...code_location import CodeLocation
26
- from .external_codeloc import ExternalCodeLocation
27
23
  from .heap_allocator import HeapAllocator
28
24
  from .subject import Subject, SubjectType
25
+ from .rd_initializer import RDAStateInitializer
29
26
 
30
27
  if TYPE_CHECKING:
31
28
  from .reaching_definitions import ReachingDefinitionsAnalysis
@@ -92,6 +89,7 @@ class ReachingDefinitionsState:
92
89
  environment: Environment = None,
93
90
  sp_adjusted: bool = False,
94
91
  all_definitions: Optional[Set[Definition]] = None,
92
+ initializer: Optional["RDAStateInitializer"] = None,
95
93
  ):
96
94
  # handy short-hands
97
95
  self.codeloc = codeloc
@@ -105,16 +103,6 @@ class ReachingDefinitionsState:
105
103
 
106
104
  self.all_definitions: Set[Definition] = set() if all_definitions is None else all_definitions
107
105
 
108
- if live_definitions is None:
109
- # the first time this state is created. initialize it
110
- self.live_definitions = LiveDefinitions(
111
- self.arch, track_tmps=self._track_tmps, canonical_size=canonical_size
112
- )
113
- self._set_initialization_values(subject, rtoc_value)
114
- else:
115
- # this state is a copy from a previous state. skip the initialization
116
- self.live_definitions = live_definitions
117
-
118
106
  self.heap_allocator = heap_allocator or HeapAllocator(canonical_size)
119
107
  self._environment: Environment = environment or Environment()
120
108
 
@@ -126,6 +114,24 @@ class ReachingDefinitionsState:
126
114
  # block and is always set to False at the beginning of the analysis of each block.
127
115
  self.exit_observed: bool = False
128
116
 
117
+ # initialize the live definitions
118
+ # This must stay at the end of the __init__ method, because the _set_initialization_values method will call
119
+ # the state initializer which might need to access some of the above attributes, e.g. the heap_allocator
120
+ # to do its job
121
+
122
+ if live_definitions is None:
123
+ # the first time this state is created. initialize it
124
+ self.live_definitions = LiveDefinitions(
125
+ self.arch, track_tmps=self._track_tmps, canonical_size=canonical_size
126
+ )
127
+ self._set_initialization_values(subject, rtoc_value, initializer=initializer)
128
+
129
+ if self.analysis is not None:
130
+ self.live_definitions.project = self.analysis.project
131
+ else:
132
+ # this state is a copy from a previous state. skip the initialization
133
+ self.live_definitions = live_definitions
134
+
129
135
  #
130
136
  # Util methods for working with the memory model
131
137
  #
@@ -136,26 +142,18 @@ class ReachingDefinitionsState:
136
142
  def is_top(self, *args):
137
143
  return self.live_definitions.is_top(*args)
138
144
 
139
- def heap_address(self, offset: int) -> claripy.ast.Base:
140
- base = claripy.BVS("heap_base", self.arch.bits, explicit_name=True)
141
- if offset:
142
- return base + offset
143
- return base
145
+ def heap_address(self, offset: Union[int, HeapAddress]) -> claripy.ast.BV:
146
+ return self.live_definitions.heap_address(offset)
144
147
 
145
148
  @staticmethod
146
149
  def is_heap_address(addr: claripy.ast.Base) -> bool:
147
- return "heap_base" in addr.variables
150
+ return LiveDefinitions.is_heap_address(addr)
148
151
 
149
152
  @staticmethod
150
153
  def get_heap_offset(addr: claripy.ast.Base) -> Optional[int]:
151
- if "heap_base" in addr.variables:
152
- if addr.op == "BVS":
153
- return 0
154
- elif addr.op == "__add__" and len(addr.args) == 2 and addr.args[1].op == "BVV":
155
- return addr.args[1]._model_concrete.value
156
- return None
154
+ return LiveDefinitions.get_heap_offset(addr)
157
155
 
158
- def stack_address(self, offset: int) -> claripy.ast.Base:
156
+ def stack_address(self, offset: int) -> claripy.ast.BV:
159
157
  return self.live_definitions.stack_address(offset)
160
158
 
161
159
  def is_stack_address(self, addr: claripy.ast.Base) -> bool:
@@ -205,7 +203,7 @@ class ReachingDefinitionsState:
205
203
  #
206
204
 
207
205
  @property
208
- def tmp_definitions(self):
206
+ def tmps(self):
209
207
  return self.live_definitions.tmps
210
208
 
211
209
  @property
@@ -217,20 +215,20 @@ class ReachingDefinitionsState:
217
215
  return self.live_definitions.register_uses
218
216
 
219
217
  @property
220
- def register_definitions(self) -> MultiValuedMemory:
221
- return self.live_definitions.register_definitions
218
+ def registers(self) -> MultiValuedMemory:
219
+ return self.live_definitions.registers
222
220
 
223
221
  @property
224
- def stack_definitions(self) -> MultiValuedMemory:
225
- return self.live_definitions.stack_definitions
222
+ def stack(self) -> MultiValuedMemory:
223
+ return self.live_definitions.stack
226
224
 
227
225
  @property
228
226
  def stack_uses(self):
229
227
  return self.live_definitions.stack_uses
230
228
 
231
229
  @property
232
- def heap_definitions(self) -> MultiValuedMemory:
233
- return self.live_definitions.heap_definitions
230
+ def heap(self) -> MultiValuedMemory:
231
+ return self.live_definitions.heap
234
232
 
235
233
  @property
236
234
  def heap_uses(self):
@@ -241,8 +239,8 @@ class ReachingDefinitionsState:
241
239
  return self.live_definitions.memory_uses
242
240
 
243
241
  @property
244
- def memory_definitions(self) -> MultiValuedMemory:
245
- return self.live_definitions.memory_definitions
242
+ def memory(self) -> MultiValuedMemory:
243
+ return self.live_definitions.memory
246
244
 
247
245
  @property
248
246
  def uses_by_codeloc(self):
@@ -270,124 +268,29 @@ class ReachingDefinitionsState:
270
268
  ctnt = "RDState-%r" % (self.live_definitions)
271
269
  return "{%s}" % ctnt
272
270
 
273
- def _set_initialization_values(self, subject: Subject, rtoc_value: Optional[int] = None):
271
+ def _set_initialization_values(
272
+ self, subject: Subject, rtoc_value: Optional[int] = None, initializer: Optional[RDAStateInitializer] = None
273
+ ):
274
+ if initializer is None:
275
+ initializer = RDAStateInitializer(self.arch)
276
+
274
277
  if subject.type == SubjectType.Function:
275
278
  if isinstance(self.arch, archinfo.arch_ppc64.ArchPPC64) and not rtoc_value:
276
279
  raise ValueError("The architecture being ppc64, the parameter `rtoc_value` should be provided.")
277
280
 
278
- self._initialize_function(
279
- subject.cc,
280
- subject.content.addr,
281
- rtoc_value,
282
- )
281
+ initializer.initialize_function_state(self, subject.cc, subject.content.addr, rtoc_value)
283
282
  elif subject.type == SubjectType.CallTrace:
284
283
  if isinstance(self.arch, archinfo.arch_ppc64.ArchPPC64) and not rtoc_value:
285
284
  raise ValueError("The architecture being ppc64, the parameter `rtoc_value` should be provided.")
286
285
 
287
- self._initialize_function(
288
- subject.cc,
289
- subject.content.current_function_address(),
290
- rtoc_value,
286
+ initializer.initialize_function_state(
287
+ self, subject.cc, subject.content.current_function_address(), rtoc_value
291
288
  )
292
289
  elif subject.type == SubjectType.Block:
293
290
  pass
294
291
 
295
292
  return self
296
293
 
297
- def _generate_call_string(self, current_address: int) -> Tuple[int, ...]:
298
- if isinstance(self._subject.content, Function):
299
- return (self._subject.content.addr,)
300
- elif isinstance(self._subject.content, CallTrace):
301
- if any(current_address == x.caller_func_addr for x in self._subject.content.callsites):
302
- callsites = iter(reversed([x.caller_func_addr for x in self._subject.content.callsites]))
303
- for call_addr in callsites:
304
- if current_address == call_addr:
305
- break
306
- return tuple(callsites)
307
- else:
308
- return tuple(x.caller_func_addr for x in self._subject.content.callsites)
309
- else:
310
- l.warning("Subject with unknown content-type")
311
- return None
312
-
313
- def _initialize_function(self, cc: SimCC, func_addr: int, rtoc_value: Optional[int] = None):
314
- # initialize stack pointer
315
- call_string = self._generate_call_string(func_addr)
316
- sp_atom = Register(self.arch.sp_offset, self.arch.bytes)
317
- sp_def = Definition(sp_atom, ExternalCodeLocation(call_string), tags={InitialValueTag()})
318
- sp = self.annotate_with_def(self._initial_stack_pointer(), sp_def)
319
- self.register_definitions.store(self.arch.sp_offset, sp)
320
-
321
- ex_loc = ExternalCodeLocation(call_string)
322
- if self.analysis is not None:
323
- self.analysis.model.at_new_stmt(ex_loc)
324
-
325
- if cc is not None:
326
- prototype = self.analysis.kb.functions[func_addr].prototype
327
- if prototype is not None:
328
- for loc in cc.arg_locs(prototype):
329
- for arg in loc.get_footprint():
330
- # initialize register parameters
331
- if isinstance(arg, SimRegArg):
332
- # FIXME: implement reg_offset handling in SimRegArg
333
- reg_offset = self.arch.registers[arg.reg_name][0]
334
- reg_atom = Register(reg_offset, self.arch.bytes)
335
- reg_def = Definition(reg_atom, ex_loc, tags={ParameterTag(function=func_addr)})
336
- self.all_definitions.add(reg_def)
337
- if self.analysis is not None:
338
- self.analysis.model.add_def(reg_def, ex_loc)
339
- reg = self.annotate_with_def(self.top(self.arch.bits), reg_def)
340
- self.register_definitions.store(reg_offset, reg)
341
-
342
- # initialize stack parameters
343
- elif isinstance(arg, SimStackArg):
344
- ml_atom = MemoryLocation(SpOffset(self.arch.bits, arg.stack_offset), arg.size)
345
- ml_def = Definition(ml_atom, ex_loc, tags={ParameterTag(function=func_addr)})
346
- self.all_definitions.add(ml_def)
347
- if self.analysis is not None:
348
- self.analysis.model.add_def(ml_def, ex_loc)
349
- ml = self.annotate_with_def(self.top(self.arch.bits), ml_def)
350
- stack_address = self.get_stack_address(self.stack_address(arg.stack_offset))
351
- self.stack_definitions.store(stack_address, ml, endness=self.arch.memory_endness)
352
- else:
353
- raise TypeError("Unsupported parameter type %s." % type(arg).__name__)
354
-
355
- # architecture dependent initialization
356
- if self.arch.name.startswith("PPC64"):
357
- if rtoc_value is None:
358
- raise TypeError("rtoc_value must be provided on PPC64.")
359
- offset, size = self.arch.registers["rtoc"]
360
- rtoc_atom = Register(offset, size)
361
- rtoc_def = Definition(rtoc_atom, ex_loc, tags={InitialValueTag()})
362
- self.all_definitions.add(rtoc_def)
363
- if self.analysis is not None:
364
- self.analysis.model.add_def(rtoc_def, ex_loc)
365
- rtoc = self.annotate_with_def(claripy.BVV(rtoc_value, self.arch.bits), rtoc_def)
366
- self.register_definitions.store(offset, rtoc)
367
- elif self.arch.name.startswith("MIPS64"):
368
- offset, size = self.arch.registers["t9"]
369
- t9_atom = Register(offset, size)
370
- t9_def = Definition(t9_atom, ex_loc, tags={InitialValueTag()})
371
- self.all_definitions.add(t9_def)
372
- if self.analysis is not None:
373
- self.analysis.model.add_def(t9_def, ex_loc)
374
- t9 = self.annotate_with_def(claripy.BVV(func_addr, self.arch.bits), t9_def)
375
- self.register_definitions.store(offset, t9)
376
- elif self.arch.name.startswith("MIPS"):
377
- if func_addr is None:
378
- l.warning("func_addr must not be None to initialize a function in mips")
379
- t9_offset = self.arch.registers["t9"][0]
380
- t9_atom = Register(t9_offset, self.arch.bytes)
381
- t9_def = Definition(t9_atom, ex_loc, tags={InitialValueTag()})
382
- self.all_definitions.add(t9_def)
383
- if self.analysis is not None:
384
- self.analysis.model.add_def(t9_def, ex_loc)
385
- t9 = self.annotate_with_def(claripy.BVV(func_addr, self.arch.bits), t9_def)
386
- self.register_definitions.store(t9_offset, t9)
387
-
388
- if self.analysis is not None:
389
- self.analysis.model.complete_loc()
390
-
391
294
  def copy(self, discard_tmpdefs=False) -> "ReachingDefinitionsState":
392
295
  rd = ReachingDefinitionsState(
393
296
  self.codeloc,
@@ -574,17 +477,33 @@ class ReachingDefinitionsState:
574
477
  self.codeloc_uses.add(definition)
575
478
  self.live_definitions.add_memory_use_by_def(definition, self.codeloc, expr=expr)
576
479
 
577
- def get_definitions(self, atom: Atom) -> Iterable[Definition]:
480
+ def get_definitions(
481
+ self, atom: Union[Atom, Definition, Iterable[Atom], Iterable[Definition]]
482
+ ) -> Iterable[Definition]:
578
483
  yield from self.live_definitions.get_definitions(atom)
579
484
 
580
- def get_values(self, spec: Union[Atom, Definition]) -> Optional[MultiValues]:
485
+ def get_values(self, spec: Union[Atom, Definition, Iterable[Atom]]) -> Optional[MultiValues]:
581
486
  return self.live_definitions.get_values(spec)
582
487
 
583
- def get_one_value(self, spec: Union[Atom, Definition]) -> Optional[claripy.ast.base.Base]:
488
+ def get_one_value(self, spec: Union[Atom, Definition]) -> Optional[claripy.ast.bv.BV]:
584
489
  return self.live_definitions.get_one_value(spec)
585
490
 
586
- def get_concrete_value(self, spec: Union[Atom, Definition]) -> Optional[int]:
587
- return self.live_definitions.get_concrete_value(spec)
491
+ @overload
492
+ def get_concrete_value(
493
+ self, spec: Union[Atom, Definition[Atom], Iterable[Atom]], cast_to: Type[int] = ...
494
+ ) -> Optional[int]:
495
+ ...
496
+
497
+ @overload
498
+ def get_concrete_value(
499
+ self, spec: Union[Atom, Definition[Atom], Iterable[Atom]], cast_to: Type[bytes] = ...
500
+ ) -> Optional[bytes]:
501
+ ...
502
+
503
+ def get_concrete_value(
504
+ self, spec: Union[Atom, Definition[Atom], Iterable[Atom]], cast_to: Union[Type[int], Type[bytes]] = int
505
+ ) -> Union[int, bytes, None]:
506
+ return self.live_definitions.get_concrete_value(spec, cast_to)
588
507
 
589
508
  def mark_guard(self, target):
590
509
  atom = GuardUse(target)
@@ -608,6 +527,7 @@ class ReachingDefinitionsState:
608
527
  self.all_definitions = set()
609
528
  self.live_definitions.reset_uses()
610
529
 
530
+ @deprecated("deref")
611
531
  def pointer_to_atoms(self, pointer: MultiValues, size: int, endness: str) -> Set[MemoryLocation]:
612
532
  """
613
533
  Given a MultiValues, return the set of atoms that loading or storing to the pointer with that value
@@ -622,6 +542,7 @@ class ReachingDefinitionsState:
622
542
 
623
543
  return result
624
544
 
545
+ @deprecated("deref")
625
546
  def pointer_to_atom(self, value: claripy.ast.base.Base, size: int, endness: str) -> Optional[MemoryLocation]:
626
547
  if self.is_top(value):
627
548
  return None
@@ -641,3 +562,24 @@ class ReachingDefinitionsState:
641
562
  return None
642
563
 
643
564
  return MemoryLocation(addr, size, endness)
565
+
566
+ @overload
567
+ def deref(
568
+ self,
569
+ pointer: Union[MultiValues, Atom, Definition, Iterable[Atom], Iterable[Definition]],
570
+ size: Union[int, DerefSize],
571
+ endness: archinfo.Endness = ...,
572
+ ) -> Set[MemoryLocation]:
573
+ ...
574
+
575
+ @overload
576
+ def deref(
577
+ self,
578
+ pointer: Union[int, claripy.ast.BV, HeapAddress, SpOffset],
579
+ size: Union[int, DerefSize],
580
+ endness: archinfo.Endness = ...,
581
+ ) -> Optional[MemoryLocation]:
582
+ ...
583
+
584
+ def deref(self, pointer, size, endness=archinfo.Endness.BE):
585
+ return self.live_definitions.deref(pointer, size, endness)
@@ -6,7 +6,6 @@ import ailment
6
6
  import pyvex
7
7
 
8
8
  from angr.analyses import ForwardAnalysis
9
- from angr.analyses.reaching_definitions.external_codeloc import ExternalCodeLocation
10
9
  from ...block import Block
11
10
  from ...knowledge_plugins.cfg.cfg_node import CFGNode
12
11
  from ...codenode import CodeNode
@@ -14,13 +13,14 @@ from ...engines.light import SimEngineLight
14
13
  from ...knowledge_plugins.functions import Function
15
14
  from ...knowledge_plugins.key_definitions import ReachingDefinitionsModel, LiveDefinitions
16
15
  from ...knowledge_plugins.key_definitions.constants import OP_BEFORE, OP_AFTER, ObservationPointType
17
- from ...code_location import CodeLocation
16
+ from ...code_location import CodeLocation, ExternalCodeLocation
18
17
  from ...misc.ux import deprecated
19
18
  from ..forward_analysis.visitors.graph import NodeType
20
19
  from ..analysis import Analysis
21
20
  from .engine_ail import SimEngineRDAIL
22
21
  from .engine_vex import SimEngineRDVEX
23
22
  from .rd_state import ReachingDefinitionsState
23
+ from .rd_initializer import RDAStateInitializer
24
24
  from .subject import Subject, SubjectType
25
25
  from .function_handler import FunctionHandler, FunctionCallRelationships
26
26
  from .dep_graph import DepGraph
@@ -61,6 +61,7 @@ class ReachingDefinitionsAnalysis(
61
61
  observation_points: "Iterable[ObservationPoint]" = None,
62
62
  init_state: ReachingDefinitionsState = None,
63
63
  init_context=None,
64
+ state_initializer: Optional["RDAStateInitializer"] = None,
64
65
  cc=None,
65
66
  function_handler: "Optional[FunctionHandler]" = None,
66
67
  observe_all=False,
@@ -70,6 +71,7 @@ class ReachingDefinitionsAnalysis(
70
71
  canonical_size=8,
71
72
  stack_pointer_tracker=None,
72
73
  use_callee_saved_regs_at_return=True,
74
+ interfunction_level: int = 0,
73
75
  ):
74
76
  """
75
77
  :param subject: The subject of the analysis: a function, or a single basic block
@@ -99,6 +101,8 @@ class ReachingDefinitionsAnalysis(
99
101
  for operations where sizes are necessary.
100
102
  :param dep_graph: Set this to True to generate a dependency graph for the subject. It will
101
103
  be available as `result.dep_graph`.
104
+ :param interfunction_level: The number of functions we should recurse into. This parameter is only
105
+ used if function_handler is not provided.
102
106
  """
103
107
 
104
108
  if isinstance(subject, str):
@@ -129,13 +133,20 @@ class ReachingDefinitionsAnalysis(
129
133
  self._dep_graph = dep_graph
130
134
 
131
135
  if function_handler is None:
132
- self._function_handler = FunctionHandler().hook(self)
136
+ self._function_handler = FunctionHandler(interfunction_level).hook(self)
133
137
  else:
138
+ if interfunction_level != 0:
139
+ l.warning("RDA(interfunction_level=XXX) doesn't do anything if you provide a function handler")
134
140
  self._function_handler = function_handler.hook(self)
135
141
 
136
142
  if self._init_state is not None:
137
143
  self._init_state = self._init_state.copy()
138
144
  self._init_state.analysis = self
145
+ # There should never be an initializer needed then
146
+ self._state_initializer = None
147
+ else:
148
+ self._state_initializer = state_initializer
149
+
139
150
  self._init_context = init_context
140
151
 
141
152
  self._observe_all = observe_all
@@ -435,6 +446,7 @@ class ReachingDefinitionsAnalysis(
435
446
  track_consts=self._track_consts,
436
447
  analysis=self,
437
448
  canonical_size=self._canonical_size,
449
+ initializer=self._state_initializer,
438
450
  )
439
451
 
440
452
  # pylint: disable=no-self-use,arguments-differ