angr 9.2.135__py3-none-manylinux2014_x86_64.whl → 9.2.137__py3-none-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/__init__.py +3 -7
- angr/analyses/analysis.py +4 -0
- angr/analyses/backward_slice.py +1 -2
- angr/analyses/binary_optimizer.py +3 -4
- angr/analyses/bindiff.py +4 -6
- angr/analyses/boyscout.py +1 -3
- angr/analyses/callee_cleanup_finder.py +4 -4
- angr/analyses/calling_convention/calling_convention.py +6 -4
- angr/analyses/calling_convention/fact_collector.py +10 -3
- angr/analyses/cdg.py +1 -2
- angr/analyses/cfg/cfb.py +1 -3
- angr/analyses/cfg/cfg.py +2 -2
- angr/analyses/cfg/cfg_base.py +40 -68
- angr/analyses/cfg/cfg_emulated.py +1 -104
- angr/analyses/cfg/cfg_fast.py +90 -27
- angr/analyses/cfg/cfg_fast_soot.py +1 -1
- angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
- angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +46 -10
- angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +5 -1
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +65 -14
- angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
- angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +24 -5
- angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +2 -5
- angr/analyses/class_identifier.py +1 -2
- angr/analyses/complete_calling_conventions.py +3 -0
- angr/analyses/congruency_check.py +2 -3
- angr/analyses/data_dep/data_dependency_analysis.py +2 -2
- angr/analyses/ddg.py +1 -4
- angr/analyses/decompiler/ail_simplifier.py +15 -5
- angr/analyses/decompiler/block_simplifier.py +2 -2
- angr/analyses/decompiler/ccall_rewriters/__init__.py +2 -0
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
- angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +69 -0
- angr/analyses/decompiler/clinic.py +119 -72
- angr/analyses/decompiler/condition_processor.py +2 -0
- angr/analyses/decompiler/decompiler.py +1 -0
- angr/analyses/decompiler/dephication/dephication_base.py +2 -0
- angr/analyses/decompiler/dephication/rewriting_engine.py +8 -6
- angr/analyses/decompiler/dephication/seqnode_dephication.py +10 -1
- angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
- angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +2 -2
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +1 -1
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +1 -2
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +1 -1
- angr/analyses/decompiler/sequence_walker.py +6 -2
- angr/analyses/decompiler/ssailification/rewriting.py +11 -1
- angr/analyses/decompiler/ssailification/rewriting_engine.py +56 -19
- angr/analyses/decompiler/ssailification/ssailification.py +13 -3
- angr/analyses/decompiler/ssailification/traversal.py +28 -2
- angr/analyses/decompiler/ssailification/traversal_state.py +6 -1
- angr/analyses/decompiler/structured_codegen/c.py +44 -21
- angr/analyses/decompiler/structuring/phoenix.py +118 -15
- angr/analyses/decompiler/utils.py +113 -8
- angr/analyses/disassembly.py +5 -5
- angr/analyses/fcp/__init__.py +4 -0
- angr/analyses/fcp/fcp.py +429 -0
- angr/analyses/identifier/identify.py +1 -3
- angr/analyses/loopfinder.py +4 -3
- angr/analyses/patchfinder.py +1 -1
- angr/analyses/propagator/engine_base.py +4 -3
- angr/analyses/propagator/propagator.py +14 -53
- angr/analyses/reaching_definitions/function_handler.py +1 -1
- angr/analyses/reassembler.py +1 -2
- angr/analyses/s_liveness.py +5 -1
- angr/analyses/s_propagator.py +26 -7
- angr/analyses/s_reaching_definitions/s_rda_model.py +2 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +20 -1
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +11 -1
- angr/analyses/soot_class_hierarchy.py +1 -2
- angr/analyses/stack_pointer_tracker.py +29 -3
- angr/analyses/static_hooker.py +1 -2
- angr/analyses/typehoon/simple_solver.py +2 -2
- angr/analyses/variable_recovery/engine_ail.py +19 -7
- angr/analyses/variable_recovery/engine_base.py +16 -14
- angr/analyses/variable_recovery/engine_vex.py +2 -2
- angr/analyses/variable_recovery/variable_recovery_fast.py +23 -3
- angr/analyses/veritesting.py +4 -7
- angr/analyses/vfg.py +1 -1
- angr/analyses/vsa_ddg.py +1 -2
- angr/block.py +62 -22
- angr/callable.py +1 -3
- angr/calling_conventions.py +3 -3
- angr/codenode.py +5 -1
- angr/concretization_strategies/__init__.py +1 -83
- angr/concretization_strategies/any.py +2 -1
- angr/concretization_strategies/any_named.py +1 -1
- angr/concretization_strategies/base.py +81 -0
- angr/concretization_strategies/controlled_data.py +2 -1
- angr/concretization_strategies/eval.py +2 -1
- angr/concretization_strategies/logging.py +3 -1
- angr/concretization_strategies/max.py +2 -1
- angr/concretization_strategies/nonzero.py +2 -1
- angr/concretization_strategies/nonzero_range.py +2 -1
- angr/concretization_strategies/norepeats.py +2 -1
- angr/concretization_strategies/norepeats_range.py +2 -1
- angr/concretization_strategies/range.py +2 -1
- angr/concretization_strategies/signed_add.py +2 -1
- angr/concretization_strategies/single.py +2 -1
- angr/concretization_strategies/solutions.py +2 -1
- angr/concretization_strategies/unlimited_range.py +2 -1
- angr/engines/__init__.py +8 -5
- angr/engines/engine.py +3 -5
- angr/engines/failure.py +4 -5
- angr/engines/pcode/emulate.py +1 -1
- angr/engines/pcode/lifter.py +31 -18
- angr/engines/procedure.py +5 -7
- angr/engines/soot/expressions/__init__.py +20 -23
- angr/engines/soot/expressions/base.py +4 -4
- angr/engines/soot/expressions/invoke.py +1 -2
- angr/engines/soot/statements/__init__.py +10 -12
- angr/engines/soot/values/__init__.py +10 -12
- angr/engines/soot/values/arrayref.py +3 -3
- angr/engines/soot/values/instancefieldref.py +3 -2
- angr/engines/successors.py +18 -12
- angr/engines/syscall.py +4 -6
- angr/engines/unicorn.py +3 -2
- angr/engines/vex/claripy/ccall.py +8 -10
- angr/engines/vex/claripy/datalayer.py +4 -5
- angr/engines/vex/lifter.py +9 -6
- angr/exploration_techniques/__init__.py +0 -2
- angr/exploration_techniques/spiller.py +1 -3
- angr/exploration_techniques/stochastic.py +2 -3
- angr/factory.py +3 -9
- angr/flirt/build_sig.py +8 -15
- angr/knowledge_plugins/cfg/cfg_model.py +20 -17
- angr/knowledge_plugins/functions/function.py +70 -79
- angr/knowledge_plugins/functions/function_manager.py +8 -7
- angr/knowledge_plugins/functions/function_parser.py +1 -1
- angr/knowledge_plugins/functions/soot_function.py +21 -24
- angr/knowledge_plugins/propagations/propagation_model.py +4 -5
- angr/knowledge_plugins/propagations/states.py +0 -511
- angr/knowledge_plugins/variables/variable_manager.py +16 -10
- angr/procedures/libc/memcpy.py +4 -4
- angr/procedures/procedure_dict.py +3 -2
- angr/protos/__init__.py +2 -5
- angr/protos/cfg_pb2.py +21 -18
- angr/protos/function_pb2.py +17 -14
- angr/protos/primitives_pb2.py +44 -39
- angr/protos/variables_pb2.py +36 -31
- angr/protos/xrefs_pb2.py +15 -12
- angr/sim_procedure.py +15 -16
- angr/sim_variable.py +13 -1
- angr/simos/__init__.py +2 -0
- angr/simos/javavm.py +4 -6
- angr/simos/xbox.py +32 -0
- angr/state_plugins/__init__.py +0 -2
- angr/state_plugins/callstack.py +4 -4
- angr/state_plugins/cgc.py +3 -2
- angr/state_plugins/gdb.py +6 -5
- angr/state_plugins/globals.py +1 -2
- angr/state_plugins/heap/heap_brk.py +1 -2
- angr/state_plugins/history.py +10 -12
- angr/state_plugins/inspect.py +3 -5
- angr/state_plugins/libc.py +2 -2
- angr/state_plugins/log.py +8 -10
- angr/state_plugins/loop_data.py +1 -2
- angr/state_plugins/posix.py +7 -7
- angr/state_plugins/preconstrainer.py +2 -3
- angr/state_plugins/scratch.py +5 -8
- angr/state_plugins/sim_action.py +3 -3
- angr/state_plugins/solver.py +8 -3
- angr/state_plugins/symbolizer.py +5 -4
- angr/state_plugins/uc_manager.py +3 -3
- angr/state_plugins/unicorn_engine.py +5 -1
- angr/state_plugins/view.py +3 -5
- angr/storage/file.py +3 -5
- angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
- angr/storage/memory_mixins/bvv_conversion_mixin.py +3 -3
- angr/storage/memory_mixins/clouseau_mixin.py +1 -3
- angr/storage/memory_mixins/name_resolution_mixin.py +1 -3
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +13 -15
- angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -22
- angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
- angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
- angr/storage/memory_mixins/paged_memory/privileged_mixin.py +3 -4
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
- angr/storage/memory_mixins/smart_find_mixin.py +1 -1
- angr/storage/memory_mixins/underconstrained_mixin.py +1 -1
- angr/storage/memory_mixins/unwrapper_mixin.py +1 -3
- angr/utils/enums_conv.py +28 -12
- angr/utils/segment_list.py +25 -22
- angr/utils/timing.py +18 -1
- angr/vaults.py +5 -6
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/METADATA +7 -7
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/RECORD +193 -191
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/WHEEL +1 -1
- angr/analyses/propagator/outdated_definition_walker.py +0 -159
- angr/analyses/propagator/tmpvar_finder.py +0 -18
- angr/engines/concrete.py +0 -180
- angr/exploration_techniques/symbion.py +0 -80
- angr/state_plugins/concrete.py +0 -295
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/LICENSE +0 -0
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/entry_points.txt +0 -0
- {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/top_level.txt +0 -0
|
@@ -17,7 +17,6 @@ from .manual_mergepoint import ManualMergepoint
|
|
|
17
17
|
from .tech_builder import TechniqueBuilder
|
|
18
18
|
from .stochastic import StochasticSearch
|
|
19
19
|
from .unique import UniqueSearch
|
|
20
|
-
from .symbion import Symbion
|
|
21
20
|
from .memory_watcher import MemoryWatcher
|
|
22
21
|
from .bucketizer import Bucketizer
|
|
23
22
|
from .local_loop_seer import LocalLoopSeer
|
|
@@ -45,7 +44,6 @@ __all__ = (
|
|
|
45
44
|
"StochasticSearch",
|
|
46
45
|
"StubStasher",
|
|
47
46
|
"Suggestions",
|
|
48
|
-
"Symbion",
|
|
49
47
|
"TechniqueBuilder",
|
|
50
48
|
"Threading",
|
|
51
49
|
"Timeout",
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
import contextlib
|
|
5
5
|
import logging
|
|
6
6
|
|
|
7
|
+
from angr import vaults
|
|
7
8
|
from .base import ExplorationTechnique
|
|
8
9
|
|
|
9
10
|
|
|
@@ -277,6 +278,3 @@ class Spiller(ExplorationTechnique):
|
|
|
277
278
|
@staticmethod
|
|
278
279
|
def state_priority(state):
|
|
279
280
|
return id(state)
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
from angr import vaults
|
|
@@ -44,13 +44,12 @@ class StochasticSearch(ExplorationTechnique):
|
|
|
44
44
|
assert len(states) >= 2
|
|
45
45
|
total_weight = sum(self.affinity[s.addr] for s in states)
|
|
46
46
|
selected = self._random.uniform(0, total_weight)
|
|
47
|
-
i = 0
|
|
48
47
|
for i, state in enumerate(states):
|
|
49
48
|
weight = self.affinity[state.addr]
|
|
50
49
|
if selected < weight:
|
|
51
|
-
|
|
50
|
+
return states[i]
|
|
52
51
|
selected -= weight
|
|
53
|
-
return states[
|
|
52
|
+
return states[len(states) - 1]
|
|
54
53
|
|
|
55
54
|
simgr.stashes[stash] = [weighted_pick(simgr.stashes[stash])]
|
|
56
55
|
|
angr/factory.py
CHANGED
|
@@ -11,7 +11,7 @@ from .sim_state import SimState
|
|
|
11
11
|
from .calling_conventions import default_cc, SimRegArg, SimStackArg, PointerWrapper, SimCCUnknown
|
|
12
12
|
from .callable import Callable
|
|
13
13
|
from .errors import AngrAssemblyError, AngrError
|
|
14
|
-
from .engines import UberEngine, ProcedureEngine
|
|
14
|
+
from .engines import UberEngine, ProcedureEngine
|
|
15
15
|
from .sim_type import SimTypeFunction, SimTypeInt
|
|
16
16
|
from .codenode import HookNode, SyscallNode
|
|
17
17
|
from .block import Block, SootBlock
|
|
@@ -39,7 +39,6 @@ class AngrObjectFactory:
|
|
|
39
39
|
project: Project
|
|
40
40
|
default_engine_factory: type[SimEngine]
|
|
41
41
|
procedure_engine: ProcedureEngine
|
|
42
|
-
concrete_engine: SimEngineConcrete | None
|
|
43
42
|
_default_cc: type[SimCC] | None
|
|
44
43
|
|
|
45
44
|
# We use thread local storage to cache engines on a per-thread basis
|
|
@@ -66,16 +65,11 @@ class AngrObjectFactory:
|
|
|
66
65
|
)
|
|
67
66
|
self.procedure_engine = ProcedureEngine(project)
|
|
68
67
|
|
|
69
|
-
if project.concrete_target:
|
|
70
|
-
self.concrete_engine = SimEngineConcrete(project)
|
|
71
|
-
else:
|
|
72
|
-
self.concrete_engine = None
|
|
73
|
-
|
|
74
68
|
def __getstate__(self):
|
|
75
|
-
return self.project, self.default_engine_factory, self.procedure_engine, self.
|
|
69
|
+
return self.project, self.default_engine_factory, self.procedure_engine, self._default_cc
|
|
76
70
|
|
|
77
71
|
def __setstate__(self, state):
|
|
78
|
-
self.project, self.default_engine_factory, self.procedure_engine, self.
|
|
72
|
+
self.project, self.default_engine_factory, self.procedure_engine, self._default_cc = state
|
|
79
73
|
self._tls = threading.local()
|
|
80
74
|
|
|
81
75
|
@property
|
angr/flirt/build_sig.py
CHANGED
|
@@ -22,9 +22,7 @@ def get_basic_info(ar_path: str) -> dict[str, str]:
|
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
24
|
with tempfile.TemporaryDirectory() as tempdirname:
|
|
25
|
-
cwd
|
|
26
|
-
os.chdir(tempdirname)
|
|
27
|
-
subprocess.call(["ar", "x", ar_path])
|
|
25
|
+
subprocess.call(["ar", "x", ar_path], cwd=tempdirname)
|
|
28
26
|
|
|
29
27
|
# Load arch and OS information from the first .o file
|
|
30
28
|
o_files = [f for f in os.listdir(".") if f.endswith(".o")]
|
|
@@ -32,8 +30,8 @@ def get_basic_info(ar_path: str) -> dict[str, str]:
|
|
|
32
30
|
proj = angr.Project(o_files[0], auto_load_libs=False)
|
|
33
31
|
arch_name = proj.arch.name.lower()
|
|
34
32
|
os_name = proj.simos.name.lower()
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
else:
|
|
34
|
+
raise ValueError("No .o files found in the archive.")
|
|
37
35
|
|
|
38
36
|
return {
|
|
39
37
|
"arch": arch_name,
|
|
@@ -64,9 +62,7 @@ def get_unique_strings(ar_path: str) -> list[str]:
|
|
|
64
62
|
# extract the archive file into a temporary directory
|
|
65
63
|
all_strings = set()
|
|
66
64
|
with tempfile.TemporaryDirectory() as tempdirname:
|
|
67
|
-
cwd
|
|
68
|
-
os.chdir(tempdirname)
|
|
69
|
-
subprocess.call(["ar", "x", ar_path])
|
|
65
|
+
subprocess.call(["ar", "x", ar_path], cwd=tempdirname)
|
|
70
66
|
|
|
71
67
|
for filename in os.listdir("."):
|
|
72
68
|
if filename.endswith(".o"):
|
|
@@ -93,8 +89,6 @@ def get_unique_strings(ar_path: str) -> list[str]:
|
|
|
93
89
|
non_symbol_strings.add(s)
|
|
94
90
|
all_strings |= non_symbol_strings
|
|
95
91
|
|
|
96
|
-
os.chdir(cwd)
|
|
97
|
-
|
|
98
92
|
grouped_strings = defaultdict(set)
|
|
99
93
|
for s in all_strings:
|
|
100
94
|
grouped_strings[s[:5]].add(s)
|
|
@@ -138,7 +132,7 @@ def process_exc_file(exc_path: str):
|
|
|
138
132
|
|
|
139
133
|
TODO: Add caller-callee-based de-duplication.
|
|
140
134
|
"""
|
|
141
|
-
with open(exc_path) as f:
|
|
135
|
+
with open(exc_path, encoding="utf-8") as f:
|
|
142
136
|
data = f.read()
|
|
143
137
|
lines = data.split("\n")
|
|
144
138
|
|
|
@@ -184,7 +178,7 @@ def process_exc_file(exc_path: str):
|
|
|
184
178
|
g[the_chosen_one] = "+" + line
|
|
185
179
|
|
|
186
180
|
# output
|
|
187
|
-
with open(exc_path, "w") as f:
|
|
181
|
+
with open(exc_path, "w", encoding="utf-8") as f:
|
|
188
182
|
for g in groups.values():
|
|
189
183
|
for line in g.values():
|
|
190
184
|
f.write(line + "\n")
|
|
@@ -273,8 +267,7 @@ def main():
|
|
|
273
267
|
basename = os.path.basename(ar_path)
|
|
274
268
|
|
|
275
269
|
# sanitize basename since otherwise sigmake is not happy with it
|
|
276
|
-
|
|
277
|
-
basename = basename[:-2]
|
|
270
|
+
basename = basename.removesuffix(".a")
|
|
278
271
|
basename = basename.replace("+", "plus")
|
|
279
272
|
|
|
280
273
|
# sanitize signame as well
|
|
@@ -292,7 +285,7 @@ def main():
|
|
|
292
285
|
|
|
293
286
|
assert not has_collision
|
|
294
287
|
|
|
295
|
-
with open(meta_path, "w") as f:
|
|
288
|
+
with open(meta_path, "w", encoding="utf-8") as f:
|
|
296
289
|
metadata = {
|
|
297
290
|
"unique_strings": unique_strings,
|
|
298
291
|
}
|
|
@@ -6,10 +6,10 @@ import logging
|
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
from collections.abc import Callable
|
|
8
8
|
from collections import defaultdict
|
|
9
|
-
import bisect
|
|
10
9
|
import string
|
|
11
10
|
|
|
12
11
|
import networkx
|
|
12
|
+
from sortedcontainers import SortedList
|
|
13
13
|
|
|
14
14
|
import cle
|
|
15
15
|
|
|
@@ -81,7 +81,7 @@ class CFGModel(Serializable):
|
|
|
81
81
|
# CFGNodes dict indexed by block ID. Don't serialize
|
|
82
82
|
self._nodes: dict[int, CFGNode] = {}
|
|
83
83
|
# addresses of CFGNodes to speed up get_any_node(..., anyaddr=True). Don't serialize
|
|
84
|
-
self._node_addrs:
|
|
84
|
+
self._node_addrs: SortedList[int] | None = None
|
|
85
85
|
|
|
86
86
|
self.normalized = False
|
|
87
87
|
|
|
@@ -137,7 +137,8 @@ class CFGModel(Serializable):
|
|
|
137
137
|
edge.dst_ea = dst.addr
|
|
138
138
|
for k, v in data.items():
|
|
139
139
|
if k == "jumpkind":
|
|
140
|
-
|
|
140
|
+
jk = cfg_jumpkind_to_pb(v)
|
|
141
|
+
edge.jumpkind = primitives_pb2.Edge.UnknownJumpkind if jk is None else jk
|
|
141
142
|
elif k == "ins_addr":
|
|
142
143
|
edge.ins_addr = v if v is not None else 0xFFFF_FFFF_FFFF_FFFF
|
|
143
144
|
elif k == "stmt_idx":
|
|
@@ -176,7 +177,7 @@ class CFGModel(Serializable):
|
|
|
176
177
|
"The resulting graph may be broken."
|
|
177
178
|
)
|
|
178
179
|
|
|
179
|
-
model._node_addrs =
|
|
180
|
+
model._node_addrs = None
|
|
180
181
|
|
|
181
182
|
# edges
|
|
182
183
|
for edge_pb2 in cmsg.edges:
|
|
@@ -219,6 +220,9 @@ class CFGModel(Serializable):
|
|
|
219
220
|
|
|
220
221
|
return model
|
|
221
222
|
|
|
223
|
+
def _build_node_addr_index(self):
|
|
224
|
+
self._node_addrs = SortedList(iter(k for k, lst in self._nodes_by_addr.items() if lst))
|
|
225
|
+
|
|
222
226
|
#
|
|
223
227
|
# Node insertion and removal
|
|
224
228
|
#
|
|
@@ -227,12 +231,8 @@ class CFGModel(Serializable):
|
|
|
227
231
|
self._nodes[block_id] = node
|
|
228
232
|
self._nodes_by_addr[node.addr].append(node)
|
|
229
233
|
|
|
230
|
-
if isinstance(node.addr, int):
|
|
231
|
-
|
|
232
|
-
if pos >= len(self._node_addrs):
|
|
233
|
-
self._node_addrs.append(node.addr)
|
|
234
|
-
elif self._node_addrs[pos] != node.addr:
|
|
235
|
-
self._node_addrs.insert(pos, node.addr)
|
|
234
|
+
if self._node_addrs is not None and isinstance(node.addr, int) and node.addr not in self._node_addrs:
|
|
235
|
+
self._node_addrs.add(node.addr)
|
|
236
236
|
|
|
237
237
|
def remove_node(self, block_id: int, node: CFGNode) -> None:
|
|
238
238
|
"""
|
|
@@ -250,10 +250,8 @@ class CFGModel(Serializable):
|
|
|
250
250
|
if not self._nodes_by_addr[node.addr]:
|
|
251
251
|
del self._nodes_by_addr[node.addr]
|
|
252
252
|
|
|
253
|
-
if isinstance(node.addr, int):
|
|
254
|
-
|
|
255
|
-
if pos < len(self._node_addrs) and self._node_addrs[pos] == node.addr:
|
|
256
|
-
self._node_addrs.pop(pos)
|
|
253
|
+
if self._node_addrs is not None and isinstance(node.addr, int) and node.addr in self._node_addrs:
|
|
254
|
+
self._node_addrs.remove(node.addr)
|
|
257
255
|
|
|
258
256
|
#
|
|
259
257
|
# CFG View
|
|
@@ -294,17 +292,22 @@ class CFGModel(Serializable):
|
|
|
294
292
|
# fastpath: directly look in the nodes list
|
|
295
293
|
if not anyaddr or addr in self._nodes_by_addr:
|
|
296
294
|
try:
|
|
297
|
-
|
|
298
|
-
|
|
295
|
+
if is_syscall is None:
|
|
296
|
+
return self._nodes_by_addr[addr][0]
|
|
297
|
+
return next(iter(node for node in self._nodes_by_addr[addr] if node.is_syscall == is_syscall))
|
|
298
|
+
except (KeyError, IndexError, StopIteration):
|
|
299
299
|
pass
|
|
300
300
|
|
|
301
301
|
if force_fastpath:
|
|
302
302
|
return None
|
|
303
303
|
|
|
304
304
|
if isinstance(addr, int):
|
|
305
|
+
if self._node_addrs is None:
|
|
306
|
+
self._build_node_addr_index()
|
|
307
|
+
|
|
305
308
|
# slower path
|
|
306
309
|
# find all potential addresses that the block may cover
|
|
307
|
-
pos =
|
|
310
|
+
pos = self._node_addrs.bisect_left(max(addr - VEX_IRSB_MAX_SIZE, 0))
|
|
308
311
|
|
|
309
312
|
is_cfgemulated = self.ident == "CFGEmulated"
|
|
310
313
|
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
# pylint:disable=too-many-boolean-expressions
|
|
1
2
|
from __future__ import annotations
|
|
2
3
|
import os
|
|
3
4
|
import logging
|
|
4
|
-
import networkx
|
|
5
5
|
import itertools
|
|
6
6
|
from collections import defaultdict
|
|
7
7
|
from collections.abc import Iterable
|
|
8
|
+
import contextlib
|
|
9
|
+
from typing import overload
|
|
8
10
|
|
|
11
|
+
import networkx
|
|
9
12
|
from itanium_demangler import parse
|
|
10
13
|
|
|
11
14
|
from cle.backends.symbol import Symbol
|
|
@@ -13,7 +16,6 @@ from archinfo.arch_arm import get_real_address_if_arm
|
|
|
13
16
|
import claripy
|
|
14
17
|
|
|
15
18
|
from angr.knowledge_plugins.cfg.memory_data import MemoryDataSort
|
|
16
|
-
|
|
17
19
|
from angr.codenode import CodeNode, BlockNode, HookNode, SyscallNode
|
|
18
20
|
from angr.serializable import Serializable
|
|
19
21
|
from angr.errors import AngrValueError, SimEngineError, SimMemoryError
|
|
@@ -22,14 +24,12 @@ from angr.procedures.definitions import SimSyscallLibrary
|
|
|
22
24
|
from angr.protos import function_pb2
|
|
23
25
|
from angr.calling_conventions import DEFAULT_CC, default_cc
|
|
24
26
|
from angr.misc.ux import deprecated
|
|
25
|
-
from .function_parser import FunctionParser
|
|
26
|
-
|
|
27
|
-
l = logging.getLogger(name=__name__)
|
|
28
|
-
|
|
29
27
|
from angr.sim_type import SimTypeFunction, parse_defns
|
|
30
28
|
from angr.calling_conventions import SimCC
|
|
31
29
|
from angr.project import Project
|
|
32
|
-
import
|
|
30
|
+
from .function_parser import FunctionParser
|
|
31
|
+
|
|
32
|
+
l = logging.getLogger(name=__name__)
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
class Function(Serializable):
|
|
@@ -41,7 +41,6 @@ class Function(Serializable):
|
|
|
41
41
|
"_addr_to_block_node",
|
|
42
42
|
"_argument_registers",
|
|
43
43
|
"_argument_stack_variables",
|
|
44
|
-
"_block_cache",
|
|
45
44
|
"_block_sizes",
|
|
46
45
|
"_call_sites",
|
|
47
46
|
"_callout_sites",
|
|
@@ -71,13 +70,10 @@ class Function(Serializable):
|
|
|
71
70
|
"is_simprocedure",
|
|
72
71
|
"is_syscall",
|
|
73
72
|
"normalized",
|
|
74
|
-
"prepared_registers",
|
|
75
|
-
"prepared_stack_variables",
|
|
76
73
|
"previous_names",
|
|
77
74
|
"prototype",
|
|
78
75
|
"prototype_libname",
|
|
79
76
|
"ran_cca",
|
|
80
|
-
"registers_read_afterwards",
|
|
81
77
|
"retaddr_on_stack",
|
|
82
78
|
"sp_delta",
|
|
83
79
|
"startpoint",
|
|
@@ -150,15 +146,11 @@ class Function(Serializable):
|
|
|
150
146
|
self.is_prototype_guessed: bool = True
|
|
151
147
|
# Whether this function returns or not. `None` means it's not determined yet
|
|
152
148
|
self._returning = None
|
|
153
|
-
self.prepared_registers = set()
|
|
154
|
-
self.prepared_stack_variables = set()
|
|
155
|
-
self.registers_read_afterwards = set()
|
|
156
149
|
|
|
157
150
|
self._addr_to_block_node = {} # map addresses to nodes. it's a cache of blocks. if a block is removed from the
|
|
158
151
|
# function, it may not be removed from _addr_to_block_node. if you want to list
|
|
159
152
|
# all blocks of a function, access .blocks.
|
|
160
153
|
self._block_sizes = {} # map addresses to block sizes
|
|
161
|
-
self._block_cache = {} # a cache of real, hard data Block objects
|
|
162
154
|
self._local_blocks = {} # a dict of all blocks inside the function
|
|
163
155
|
self._local_block_addrs = set() # a set of addresses of all blocks inside the function
|
|
164
156
|
|
|
@@ -374,13 +366,6 @@ class Function(Serializable):
|
|
|
374
366
|
:param byte_string:
|
|
375
367
|
:return:
|
|
376
368
|
"""
|
|
377
|
-
if addr in self._block_cache:
|
|
378
|
-
b = self._block_cache[addr]
|
|
379
|
-
if size is None or b.size == size:
|
|
380
|
-
return b
|
|
381
|
-
# size seems to be updated. remove this cached entry from the block cache
|
|
382
|
-
del self._block_cache[addr]
|
|
383
|
-
|
|
384
369
|
if size is None and addr in self.block_addrs:
|
|
385
370
|
# we know the size
|
|
386
371
|
size = self._block_sizes[addr]
|
|
@@ -389,7 +374,6 @@ class Function(Serializable):
|
|
|
389
374
|
if size is None:
|
|
390
375
|
# update block_size dict
|
|
391
376
|
self._block_sizes[addr] = block.size
|
|
392
|
-
self._block_cache[addr] = block
|
|
393
377
|
return block
|
|
394
378
|
|
|
395
379
|
# compatibility
|
|
@@ -440,7 +424,7 @@ class Function(Serializable):
|
|
|
440
424
|
|
|
441
425
|
@classmethod
|
|
442
426
|
def _get_cmsg(cls):
|
|
443
|
-
return function_pb2.Function()
|
|
427
|
+
return function_pb2.Function() # pylint:disable=no-member
|
|
444
428
|
|
|
445
429
|
def serialize_to_cmessage(self):
|
|
446
430
|
return FunctionParser.serialize(self)
|
|
@@ -613,7 +597,6 @@ class Function(Serializable):
|
|
|
613
597
|
d["_local_transition_graph"] = None
|
|
614
598
|
d["_project"] = None
|
|
615
599
|
d["_function_manager"] = None
|
|
616
|
-
d["_block_cache"] = {}
|
|
617
600
|
return d
|
|
618
601
|
|
|
619
602
|
@property
|
|
@@ -642,7 +625,7 @@ class Function(Serializable):
|
|
|
642
625
|
|
|
643
626
|
@property
|
|
644
627
|
def size(self):
|
|
645
|
-
return sum(
|
|
628
|
+
return sum(b.size for b in self.blocks)
|
|
646
629
|
|
|
647
630
|
@property
|
|
648
631
|
def binary(self):
|
|
@@ -675,7 +658,7 @@ class Function(Serializable):
|
|
|
675
658
|
dec = self.project.analyses.Decompiler(self, cfg=self._function_manager._kb.cfgs.get_most_accurate())
|
|
676
659
|
return dec.codegen.text
|
|
677
660
|
|
|
678
|
-
def add_jumpout_site(self, node):
|
|
661
|
+
def add_jumpout_site(self, node: CodeNode):
|
|
679
662
|
"""
|
|
680
663
|
Add a custom jumpout site.
|
|
681
664
|
|
|
@@ -683,11 +666,11 @@ class Function(Serializable):
|
|
|
683
666
|
:return: None
|
|
684
667
|
"""
|
|
685
668
|
|
|
686
|
-
self.
|
|
669
|
+
node = self._register_node(True, node)
|
|
687
670
|
self._jumpout_sites.add(node)
|
|
688
671
|
self._add_endpoint(node, "transition")
|
|
689
672
|
|
|
690
|
-
def add_retout_site(self, node):
|
|
673
|
+
def add_retout_site(self, node: CodeNode):
|
|
691
674
|
"""
|
|
692
675
|
Add a custom retout site.
|
|
693
676
|
|
|
@@ -703,7 +686,7 @@ class Function(Serializable):
|
|
|
703
686
|
:return: None
|
|
704
687
|
"""
|
|
705
688
|
|
|
706
|
-
self.
|
|
689
|
+
node = self._register_node(True, node)
|
|
707
690
|
self._retout_sites.add(node)
|
|
708
691
|
self._add_endpoint(node, "return")
|
|
709
692
|
|
|
@@ -785,7 +768,6 @@ class Function(Serializable):
|
|
|
785
768
|
return None
|
|
786
769
|
|
|
787
770
|
def _clear_transition_graph(self):
|
|
788
|
-
self._block_cache = {}
|
|
789
771
|
self._block_sizes = {}
|
|
790
772
|
self._addr_to_block_node = {}
|
|
791
773
|
self._local_blocks = {}
|
|
@@ -812,11 +794,13 @@ class Function(Serializable):
|
|
|
812
794
|
|
|
813
795
|
# it's confirmed. register the node if needed
|
|
814
796
|
if "outside" not in data or data["outside"] is False:
|
|
815
|
-
self.
|
|
797
|
+
dst = self._register_node(True, dst)
|
|
816
798
|
|
|
817
799
|
self.transition_graph[src][dst]["confirmed"] = True
|
|
818
800
|
|
|
819
|
-
def _transit_to(
|
|
801
|
+
def _transit_to(
|
|
802
|
+
self, from_node: CodeNode, to_node, outside=False, ins_addr=None, stmt_idx=None, is_exception=False
|
|
803
|
+
):
|
|
820
804
|
"""
|
|
821
805
|
Registers an edge between basic blocks in this function's transition graph.
|
|
822
806
|
Arguments are CodeNode objects.
|
|
@@ -830,16 +814,15 @@ class Function(Serializable):
|
|
|
830
814
|
"""
|
|
831
815
|
|
|
832
816
|
if outside:
|
|
833
|
-
self.
|
|
817
|
+
from_node = self._register_node(True, from_node)
|
|
834
818
|
if to_node is not None:
|
|
835
|
-
self.
|
|
819
|
+
to_node = self._register_node(False, to_node)
|
|
836
820
|
|
|
837
821
|
self._jumpout_sites.add(from_node)
|
|
838
822
|
else:
|
|
823
|
+
from_node = self._register_node(True, from_node)
|
|
839
824
|
if to_node is not None:
|
|
840
|
-
self.
|
|
841
|
-
else:
|
|
842
|
-
self._register_nodes(True, from_node)
|
|
825
|
+
to_node = self._register_node(True, to_node)
|
|
843
826
|
|
|
844
827
|
type_ = "transition" if not is_exception else "exception"
|
|
845
828
|
if to_node is not None:
|
|
@@ -871,19 +854,22 @@ class Function(Serializable):
|
|
|
871
854
|
:type ins_addr: int or None
|
|
872
855
|
"""
|
|
873
856
|
|
|
874
|
-
self.
|
|
857
|
+
from_node = self._register_node(True, from_node)
|
|
875
858
|
|
|
876
859
|
if to_func.is_syscall:
|
|
877
860
|
self.transition_graph.add_edge(from_node, to_func, type="syscall", stmt_idx=stmt_idx, ins_addr=ins_addr)
|
|
878
861
|
else:
|
|
879
862
|
self.transition_graph.add_edge(from_node, to_func, type="call", stmt_idx=stmt_idx, ins_addr=ins_addr)
|
|
880
863
|
if ret_node is not None:
|
|
864
|
+
ret_node = self._register_node(return_to_outside is False, ret_node)
|
|
881
865
|
self._fakeret_to(from_node, ret_node, to_outside=return_to_outside)
|
|
882
866
|
|
|
883
867
|
self._local_transition_graph = None
|
|
884
868
|
|
|
885
869
|
def _fakeret_to(self, from_node, to_node, confirmed=None, to_outside=False):
|
|
886
|
-
self.
|
|
870
|
+
from_node = self._register_node(True, from_node)
|
|
871
|
+
if confirmed:
|
|
872
|
+
to_node = self._register_node(not to_outside, to_node)
|
|
887
873
|
|
|
888
874
|
if confirmed is None:
|
|
889
875
|
self.transition_graph.add_edge(from_node, to_node, type="fake_return", outside=to_outside)
|
|
@@ -891,8 +877,6 @@ class Function(Serializable):
|
|
|
891
877
|
self.transition_graph.add_edge(
|
|
892
878
|
from_node, to_node, type="fake_return", confirmed=confirmed, outside=to_outside
|
|
893
879
|
)
|
|
894
|
-
if confirmed:
|
|
895
|
-
self._register_nodes(not to_outside, to_node)
|
|
896
880
|
|
|
897
881
|
self._local_transition_graph = None
|
|
898
882
|
|
|
@@ -910,45 +894,56 @@ class Function(Serializable):
|
|
|
910
894
|
self._local_transition_graph = None
|
|
911
895
|
|
|
912
896
|
def _update_local_blocks(self, node: CodeNode):
|
|
913
|
-
self._local_blocks[node.addr]
|
|
914
|
-
|
|
897
|
+
if node.addr not in self._local_blocks or self._local_blocks[node.addr] != node:
|
|
898
|
+
self._local_blocks[node.addr] = node
|
|
899
|
+
self._local_block_addrs.add(node.addr)
|
|
915
900
|
|
|
916
901
|
def _update_addr_to_block_cache(self, node: BlockNode):
|
|
917
902
|
if node.addr not in self._addr_to_block_node:
|
|
918
903
|
self._addr_to_block_node[node.addr] = node
|
|
919
904
|
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
905
|
+
@overload
|
|
906
|
+
def _register_node(self, is_local: bool, node: CodeNode) -> CodeNode: ...
|
|
907
|
+
|
|
908
|
+
@overload
|
|
909
|
+
def _register_node(self, is_local: bool, node: Function) -> Function: ...
|
|
910
|
+
|
|
911
|
+
def _register_node(self, is_local: bool, node: CodeNode | Function) -> CodeNode | Function:
|
|
912
|
+
# if the node already exists and is the same, we reuse the existing node
|
|
913
|
+
if is_local and self._local_blocks.get(node.addr, None) == node:
|
|
914
|
+
return self._local_blocks[node.addr]
|
|
915
|
+
|
|
916
|
+
if node.addr not in self and node not in self.transition_graph:
|
|
917
|
+
# only add each node to the graph once
|
|
918
|
+
self.transition_graph.add_node(node)
|
|
919
|
+
|
|
920
|
+
if not isinstance(node, CodeNode):
|
|
921
|
+
# function and other things bail here
|
|
922
|
+
return node
|
|
923
|
+
|
|
924
|
+
# this is either a new node or a different node at the same address
|
|
925
|
+
node._graph = self.transition_graph
|
|
926
|
+
if self._block_sizes.get(node.addr, 0) == 0:
|
|
927
|
+
self._block_sizes[node.addr] = node.size
|
|
928
|
+
if node.addr == self.addr and (self.startpoint is None or not self.startpoint.is_hook):
|
|
929
|
+
self.startpoint = node
|
|
930
|
+
if is_local and node.addr not in self._local_blocks:
|
|
931
|
+
self._update_local_blocks(node)
|
|
932
|
+
# add BlockNodes to the addr_to_block_node cache if not already there
|
|
933
|
+
if isinstance(node, BlockNode):
|
|
934
|
+
self._update_addr_to_block_cache(node)
|
|
935
|
+
# else:
|
|
936
|
+
# # checks that we don't have multiple block nodes at a single address
|
|
937
|
+
# assert node == self._addr_to_block_node[node.addr]
|
|
938
|
+
return node
|
|
939
|
+
|
|
940
|
+
def _add_return_site(self, return_site: CodeNode):
|
|
946
941
|
"""
|
|
947
942
|
Registers a basic block as a site for control flow to return from this function.
|
|
948
943
|
|
|
949
|
-
:param
|
|
944
|
+
:param return_site: The block node that ends with a return.
|
|
950
945
|
"""
|
|
951
|
-
self.
|
|
946
|
+
return_site = self._register_node(True, return_site)
|
|
952
947
|
|
|
953
948
|
self._ret_sites.add(return_site)
|
|
954
949
|
# A return site must be an endpoint of the function - you cannot continue execution of the current function
|
|
@@ -1285,8 +1280,8 @@ class Function(Serializable):
|
|
|
1285
1280
|
"""
|
|
1286
1281
|
Draw the graph and save it to a PNG file.
|
|
1287
1282
|
"""
|
|
1288
|
-
import matplotlib.pyplot as pyplot # pylint: disable=import-error
|
|
1289
|
-
from networkx.drawing.nx_agraph import graphviz_layout # pylint: disable=import-error
|
|
1283
|
+
import matplotlib.pyplot as pyplot # pylint: disable=import-error,import-outside-toplevel
|
|
1284
|
+
from networkx.drawing.nx_agraph import graphviz_layout # pylint: disable=import-error,import-outside-toplevel
|
|
1290
1285
|
|
|
1291
1286
|
tmp_graph = networkx.classes.digraph.DiGraph()
|
|
1292
1287
|
for from_block, to_block in self.transition_graph.edges():
|
|
@@ -1416,11 +1411,8 @@ class Function(Serializable):
|
|
|
1416
1411
|
self._local_blocks[n.addr] = new_node
|
|
1417
1412
|
|
|
1418
1413
|
# update block_cache and block_sizes
|
|
1419
|
-
if
|
|
1420
|
-
n.addr in self._block_sizes and self._block_sizes[n.addr] != new_node.size
|
|
1421
|
-
):
|
|
1414
|
+
if n.addr in self._block_sizes and self._block_sizes[n.addr] != new_node.size:
|
|
1422
1415
|
# the cache needs updating
|
|
1423
|
-
self._block_cache.pop(n.addr, None)
|
|
1424
1416
|
self._block_sizes[n.addr] = new_node.size
|
|
1425
1417
|
|
|
1426
1418
|
for p, _, data in original_predecessors:
|
|
@@ -1680,7 +1672,6 @@ class Function(Serializable):
|
|
|
1680
1672
|
func.startpoint = self.startpoint
|
|
1681
1673
|
func._addr_to_block_node = self._addr_to_block_node.copy()
|
|
1682
1674
|
func._block_sizes = self._block_sizes.copy()
|
|
1683
|
-
func._block_cache = self._block_cache.copy()
|
|
1684
1675
|
func._local_blocks = self._local_blocks.copy()
|
|
1685
1676
|
func._local_block_addrs = self._local_block_addrs.copy()
|
|
1686
1677
|
func.info = self.info.copy()
|