angr 9.2.65__py3-none-manylinux2014_x86_64.whl → 9.2.66__py3-none-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +55 -2
- angr/analyses/calling_convention.py +4 -3
- angr/analyses/cfg/cfg_base.py +2 -2
- angr/analyses/cfg/cfg_fast.py +128 -60
- angr/analyses/decompiler/ail_simplifier.py +1 -2
- angr/analyses/decompiler/block_simplifier.py +4 -3
- angr/analyses/decompiler/callsite_maker.py +1 -1
- angr/analyses/decompiler/condition_processor.py +5 -3
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +51 -8
- angr/analyses/decompiler/peephole_optimizations/__init__.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +92 -0
- angr/analyses/decompiler/structured_codegen/c.py +59 -6
- angr/analyses/decompiler/utils.py +1 -1
- angr/analyses/find_objects_static.py +4 -4
- angr/analyses/propagator/engine_ail.py +2 -1
- angr/analyses/reaching_definitions/__init__.py +1 -3
- angr/analyses/reaching_definitions/dep_graph.py +33 -4
- angr/analyses/reaching_definitions/engine_ail.py +5 -6
- angr/analyses/reaching_definitions/engine_vex.py +6 -7
- angr/analyses/reaching_definitions/external_codeloc.py +0 -27
- angr/analyses/reaching_definitions/function_handler.py +145 -23
- angr/analyses/reaching_definitions/rd_initializer.py +221 -0
- angr/analyses/reaching_definitions/rd_state.py +95 -153
- angr/analyses/reaching_definitions/reaching_definitions.py +15 -3
- angr/calling_conventions.py +2 -2
- angr/code_location.py +24 -0
- angr/exploration_techniques/__init__.py +28 -0
- angr/knowledge_plugins/cfg/cfg_model.py +1 -1
- angr/knowledge_plugins/key_definitions/__init__.py +12 -1
- angr/knowledge_plugins/key_definitions/atoms.py +9 -0
- angr/knowledge_plugins/key_definitions/definition.py +13 -18
- angr/knowledge_plugins/key_definitions/live_definitions.py +350 -106
- angr/project.py +1 -1
- angr/sim_manager.py +15 -0
- angr/sim_state.py +3 -3
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +56 -8
- angr/storage/memory_object.py +3 -1
- angr/utils/typing.py +16 -0
- {angr-9.2.65.dist-info → angr-9.2.66.dist-info}/METADATA +7 -7
- {angr-9.2.65.dist-info → angr-9.2.66.dist-info}/RECORD +43 -41
- angr/analyses/decompiler/peephole_optimizations/conv_const_mull_a_shift.py +0 -75
- {angr-9.2.65.dist-info → angr-9.2.66.dist-info}/LICENSE +0 -0
- {angr-9.2.65.dist-info → angr-9.2.66.dist-info}/WHEEL +0 -0
- {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
|
|
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.
|
|
140
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
|
221
|
-
return self.live_definitions.
|
|
218
|
+
def registers(self) -> MultiValuedMemory:
|
|
219
|
+
return self.live_definitions.registers
|
|
222
220
|
|
|
223
221
|
@property
|
|
224
|
-
def
|
|
225
|
-
return self.live_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
|
|
233
|
-
return self.live_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
|
|
245
|
-
return self.live_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(
|
|
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.
|
|
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
|
-
|
|
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(
|
|
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.
|
|
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
|
-
|
|
587
|
-
|
|
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
|