angr 9.2.120__py3-none-manylinux2014_aarch64.whl → 9.2.122__py3-none-manylinux2014_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/cfg/cfg_fast.py +2 -1
- angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
- angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +2 -0
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +10 -6
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +138 -367
- angr/analyses/cfg/indirect_jump_resolvers/mips_elf_got.py +148 -0
- angr/analyses/decompiler/callsite_maker.py +11 -1
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +20 -0
- angr/analyses/typehoon/typevars.py +37 -16
- angr/angrdb/db.py +1 -1
- angr/block.py +9 -1
- angr/calling_conventions.py +1 -1
- angr/engines/engine.py +8 -15
- angr/engines/pcode/lifter.py +8 -0
- angr/engines/successors.py +1 -1
- angr/engines/vex/claripy/ccall.py +1 -1
- angr/engines/vex/claripy/datalayer.py +7 -10
- angr/engines/vex/heavy/actions.py +19 -24
- angr/engines/vex/heavy/heavy.py +7 -1
- angr/engines/vex/lifter.py +3 -1
- angr/engines/vex/light/light.py +2 -2
- angr/factory.py +5 -0
- angr/knowledge_plugins/cfg/memory_data.py +1 -0
- angr/lib/angr_native.so +0 -0
- angr/protos/cfg_pb2.py +23 -15
- angr/protos/function_pb2.py +19 -21
- angr/protos/primitives_pb2.py +46 -112
- angr/protos/variables_pb2.py +38 -114
- angr/protos/xrefs_pb2.py +17 -18
- angr/sim_state.py +2 -78
- angr/sim_type.py +53 -18
- angr/state_plugins/solver.py +72 -15
- angr/storage/__init__.py +1 -2
- angr/storage/memory_mixins/__init__.py +5 -160
- angr/storage/memory_mixins/actions_mixin.py +1 -1
- angr/storage/memory_mixins/address_concretization_mixin.py +1 -1
- angr/storage/memory_mixins/bvv_conversion_mixin.py +1 -1
- angr/storage/memory_mixins/clouseau_mixin.py +2 -1
- angr/storage/memory_mixins/conditional_store_mixin.py +1 -1
- angr/storage/memory_mixins/convenient_mappings_mixin.py +1 -1
- angr/storage/memory_mixins/default_filler_mixin.py +1 -1
- angr/storage/memory_mixins/dirty_addrs_mixin.py +2 -1
- angr/storage/memory_mixins/hex_dumper_mixin.py +1 -1
- angr/storage/memory_mixins/javavm_memory_mixin.py +1 -1
- angr/storage/memory_mixins/keyvalue_memory_mixin.py +1 -1
- angr/storage/memory_mixins/label_merger_mixin.py +1 -1
- angr/storage/memory_mixins/memory_mixin.py +163 -0
- angr/storage/memory_mixins/multi_value_merger_mixin.py +1 -1
- angr/storage/memory_mixins/name_resolution_mixin.py +3 -1
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -1
- angr/storage/memory_mixins/paged_memory/paged_memory_multivalue_mixin.py +2 -1
- angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/history_tracking_mixin.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +2 -1
- angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/refcount_mixin.py +2 -1
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +1 -1
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +1 -2
- angr/storage/memory_mixins/regioned_memory/region_category_mixin.py +2 -1
- angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +1 -1
- angr/storage/memory_mixins/regioned_memory/regioned_address_concretization_mixin.py +1 -1
- angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +2 -2
- angr/storage/memory_mixins/simple_interface_mixin.py +2 -1
- angr/storage/memory_mixins/simplification_mixin.py +2 -1
- angr/storage/memory_mixins/size_resolution_mixin.py +1 -1
- angr/storage/memory_mixins/slotted_memory.py +2 -2
- angr/storage/memory_mixins/smart_find_mixin.py +1 -1
- angr/storage/memory_mixins/symbolic_merger_mixin.py +2 -1
- angr/storage/memory_mixins/top_merger_mixin.py +3 -2
- angr/storage/memory_mixins/underconstrained_mixin.py +4 -2
- angr/storage/memory_mixins/unwrapper_mixin.py +2 -1
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/METADATA +7 -7
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/RECORD +78 -76
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/LICENSE +0 -0
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/WHEEL +0 -0
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/entry_points.txt +0 -0
- {angr-9.2.120.dist-info → angr-9.2.122.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# pylint:disable=too-many-positional-arguments
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from capstone.mips_const import (
|
|
6
|
+
MIPS_REG_T7,
|
|
7
|
+
MIPS_REG_T8,
|
|
8
|
+
MIPS_REG_T9,
|
|
9
|
+
MIPS_REG_RA,
|
|
10
|
+
MIPS_REG_ZERO,
|
|
11
|
+
MIPS_OP_REG,
|
|
12
|
+
MIPS_OP_IMM,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
import cle
|
|
16
|
+
|
|
17
|
+
from .resolver import IndirectJumpResolver
|
|
18
|
+
|
|
19
|
+
l = logging.getLogger(name=__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MipsElfGotResolver(IndirectJumpResolver):
|
|
23
|
+
"""
|
|
24
|
+
A timeless indirect jump resolver that resolves GOT stub entries in MIPS ELF binaries.
|
|
25
|
+
|
|
26
|
+
Reference: MIPS Assembly Language Programmer's Guide, Calling Position Independent Functions
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, project):
|
|
30
|
+
super().__init__(project, timeless=True)
|
|
31
|
+
|
|
32
|
+
self._section_cache: dict[tuple[int, str], int] = {}
|
|
33
|
+
self._simproc_cache: dict[str, int] | None = None
|
|
34
|
+
|
|
35
|
+
def filter(self, cfg, addr, func_addr, block, jumpkind):
|
|
36
|
+
return jumpkind == "Ijk_Call" and addr == func_addr
|
|
37
|
+
|
|
38
|
+
def resolve( # pylint:disable=unused-argument
|
|
39
|
+
self, cfg, addr, func_addr, block, jumpkind, func_graph_complete: bool = True, **kwargs
|
|
40
|
+
):
|
|
41
|
+
# The stub must look like the following:
|
|
42
|
+
# 585b80 lw $t9, -0x7ff0($gp)
|
|
43
|
+
# 585b84 move $t7, $ra
|
|
44
|
+
# 585b88 jalr $t9
|
|
45
|
+
# 585b8c addiu $t8, $zero, 0x84b
|
|
46
|
+
|
|
47
|
+
obj = self.project.loader.find_object_containing(addr)
|
|
48
|
+
if obj is None:
|
|
49
|
+
return False, []
|
|
50
|
+
if not isinstance(obj, cle.ELF):
|
|
51
|
+
return False, []
|
|
52
|
+
dynsym_addr = self._find_and_cache_section_addr(obj, ".dynsym")
|
|
53
|
+
if dynsym_addr is None:
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
dynstr_addr = self._find_and_cache_section_addr(obj, ".dynstr")
|
|
57
|
+
if dynstr_addr is None:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
if block.size != 16:
|
|
61
|
+
return False, []
|
|
62
|
+
the_block = self.project.factory.block(block.addr, size=block.size)
|
|
63
|
+
if len(the_block.capstone.insns) != 4:
|
|
64
|
+
return False, []
|
|
65
|
+
|
|
66
|
+
insn0 = the_block.capstone.insns[0]
|
|
67
|
+
if not (
|
|
68
|
+
insn0.insn.mnemonic == "lw"
|
|
69
|
+
and insn0.insn.operands[0].type == MIPS_OP_REG
|
|
70
|
+
and insn0.insn.operands[0].reg == MIPS_REG_T9
|
|
71
|
+
):
|
|
72
|
+
return False, []
|
|
73
|
+
|
|
74
|
+
insn1 = the_block.capstone.insns[1]
|
|
75
|
+
if not (
|
|
76
|
+
insn1.insn.mnemonic == "move"
|
|
77
|
+
and insn1.insn.operands[0].type == MIPS_OP_REG
|
|
78
|
+
and insn1.insn.operands[0].reg == MIPS_REG_T7
|
|
79
|
+
and insn1.insn.operands[1].type == MIPS_OP_REG
|
|
80
|
+
and insn1.insn.operands[1].reg == MIPS_REG_RA
|
|
81
|
+
):
|
|
82
|
+
return False, []
|
|
83
|
+
|
|
84
|
+
insn2 = the_block.capstone.insns[2]
|
|
85
|
+
if not (
|
|
86
|
+
insn2.insn.mnemonic == "jalr"
|
|
87
|
+
and insn2.insn.operands[0].type == MIPS_OP_REG
|
|
88
|
+
and insn2.insn.operands[0].reg == MIPS_REG_T9
|
|
89
|
+
):
|
|
90
|
+
return False, []
|
|
91
|
+
|
|
92
|
+
insn3 = the_block.capstone.insns[3]
|
|
93
|
+
if not (
|
|
94
|
+
insn3.insn.mnemonic == "addiu"
|
|
95
|
+
and insn3.insn.operands[0].type == MIPS_OP_REG
|
|
96
|
+
and insn3.insn.operands[0].reg == MIPS_REG_T8
|
|
97
|
+
and insn3.insn.operands[1].type == MIPS_OP_REG
|
|
98
|
+
and insn3.insn.operands[1].reg == MIPS_REG_ZERO
|
|
99
|
+
and insn3.insn.operands[2].type == MIPS_OP_IMM
|
|
100
|
+
):
|
|
101
|
+
return False, []
|
|
102
|
+
|
|
103
|
+
dynsym_index = insn3.insn.operands[2].imm
|
|
104
|
+
symbol_addr = dynsym_addr + dynsym_index * 16
|
|
105
|
+
|
|
106
|
+
symbol_name_index = self.project.loader.memory.unpack_word(symbol_addr, size=4)
|
|
107
|
+
symbol_name_addr = dynstr_addr + symbol_name_index
|
|
108
|
+
symbol_name_bytes = self.project.loader.memory.load_null_terminated_bytes(symbol_name_addr, 512)
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
symbol_name = symbol_name_bytes.strip(b"\x00").decode("ascii")
|
|
112
|
+
except UnicodeDecodeError:
|
|
113
|
+
return False, []
|
|
114
|
+
|
|
115
|
+
symbol = obj.symbols_by_name.get(symbol_name, None)
|
|
116
|
+
if symbol is None:
|
|
117
|
+
return False, []
|
|
118
|
+
|
|
119
|
+
if symbol.rebased_addr != func_addr:
|
|
120
|
+
l.debug("Resolved target to %s @ %#x", symbol_name, symbol.rebased_addr)
|
|
121
|
+
return True, [symbol.rebased_addr]
|
|
122
|
+
|
|
123
|
+
# find out if there is a SimProcedure for this import symbol
|
|
124
|
+
simproc_addr = self._cache_and_find_simproc_by_name(symbol_name)
|
|
125
|
+
if simproc_addr is not None:
|
|
126
|
+
l.debug("Resolved target to %s @ %#x", symbol_name, simproc_addr)
|
|
127
|
+
return True, [simproc_addr]
|
|
128
|
+
return False, []
|
|
129
|
+
|
|
130
|
+
def _find_and_cache_section_addr(self, obj, section_name: str) -> int | None:
|
|
131
|
+
cache_key = (obj.min_addr, section_name)
|
|
132
|
+
if cache_key in self._section_cache:
|
|
133
|
+
return self._section_cache[cache_key]
|
|
134
|
+
|
|
135
|
+
for sec in obj.sections:
|
|
136
|
+
if sec.name == section_name:
|
|
137
|
+
# cache it
|
|
138
|
+
self._section_cache[cache_key] = sec.vaddr
|
|
139
|
+
return sec.vaddr
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
def _cache_and_find_simproc_by_name(self, symbol_name: str) -> int | None:
|
|
143
|
+
if self._simproc_cache is None:
|
|
144
|
+
self._simproc_cache = {}
|
|
145
|
+
for addr, simproc in self.project._sim_procedures.items():
|
|
146
|
+
self._simproc_cache[simproc.display_name] = addr
|
|
147
|
+
|
|
148
|
+
return self._simproc_cache.get(symbol_name)
|
|
@@ -8,7 +8,7 @@ from ailment import Stmt, Expr, Const
|
|
|
8
8
|
|
|
9
9
|
from angr.procedures.stubs.format_parser import FormatParser, FormatSpecifier
|
|
10
10
|
from angr.sim_type import SimTypeBottom, SimTypePointer, SimTypeChar, SimTypeInt, dereference_simtype
|
|
11
|
-
from angr.calling_conventions import SimRegArg, SimStackArg, SimCC, SimStructArg
|
|
11
|
+
from angr.calling_conventions import SimRegArg, SimStackArg, SimCC, SimStructArg, SimComboArg
|
|
12
12
|
from angr.knowledge_plugins.key_definitions.constants import OP_BEFORE
|
|
13
13
|
from angr.analyses import Analysis, register_analysis
|
|
14
14
|
from angr.analyses.s_reaching_definitions import SRDAView
|
|
@@ -129,7 +129,17 @@ class CallSiteMaker(Analysis):
|
|
|
129
129
|
arg_locs = cc.arg_locs(callsite_ty)
|
|
130
130
|
|
|
131
131
|
if arg_locs is not None:
|
|
132
|
+
expanded_arg_locs = []
|
|
132
133
|
for arg_loc in arg_locs:
|
|
134
|
+
if isinstance(arg_loc, SimComboArg):
|
|
135
|
+
# a ComboArg spans across multiple locations (mostly stack but *in theory* can also be spanning
|
|
136
|
+
# across registers). most importantly, a ComboArg represents one variable, not multiple, but we
|
|
137
|
+
# have no way to know that until later down the pipeline.
|
|
138
|
+
expanded_arg_locs += arg_loc.locations
|
|
139
|
+
else:
|
|
140
|
+
expanded_arg_locs.append(arg_loc)
|
|
141
|
+
|
|
142
|
+
for arg_loc in expanded_arg_locs:
|
|
133
143
|
if isinstance(arg_loc, SimRegArg):
|
|
134
144
|
size = arg_loc.size
|
|
135
145
|
offset = arg_loc.check_offset(cc.arch)
|
|
@@ -240,6 +240,26 @@ class AMD64CCallRewriter(CCallRewriterBase):
|
|
|
240
240
|
|
|
241
241
|
r = Expr.BinaryOp(ccall.idx, expr_op, (masked_dep, zero), False, **ccall.tags)
|
|
242
242
|
return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
|
|
243
|
+
if op_v in {
|
|
244
|
+
AMD64_OpTypes["G_CC_OP_DECB"],
|
|
245
|
+
AMD64_OpTypes["G_CC_OP_DECW"],
|
|
246
|
+
AMD64_OpTypes["G_CC_OP_DECL"],
|
|
247
|
+
AMD64_OpTypes["G_CC_OP_DECQ"],
|
|
248
|
+
}:
|
|
249
|
+
# dep_1 == 0 or dep_1 != 0
|
|
250
|
+
dep_1 = self._fix_size(
|
|
251
|
+
dep_1,
|
|
252
|
+
op_v,
|
|
253
|
+
AMD64_OpTypes["G_CC_OP_SHRB"],
|
|
254
|
+
AMD64_OpTypes["G_CC_OP_SHRW"],
|
|
255
|
+
AMD64_OpTypes["G_CC_OP_SHRL"],
|
|
256
|
+
ccall.tags,
|
|
257
|
+
)
|
|
258
|
+
expr_op = "CmpEQ" if cond_v == AMD64_CondTypes["CondZ"] else "CmpNE"
|
|
259
|
+
|
|
260
|
+
zero = Expr.Const(None, None, 0, dep_1.bits)
|
|
261
|
+
r = Expr.BinaryOp(ccall.idx, expr_op, (dep_1, zero), False, **ccall.tags)
|
|
262
|
+
return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
|
|
243
263
|
elif cond_v == AMD64_CondTypes["CondL"]:
|
|
244
264
|
if op_v in {
|
|
245
265
|
AMD64_OpTypes["G_CC_OP_SUBB"],
|
|
@@ -28,11 +28,13 @@ class Equivalence(TypeConstraint):
|
|
|
28
28
|
__slots__ = (
|
|
29
29
|
"type_a",
|
|
30
30
|
"type_b",
|
|
31
|
+
"_cached_hash",
|
|
31
32
|
)
|
|
32
33
|
|
|
33
34
|
def __init__(self, type_a, type_b):
|
|
34
35
|
self.type_a = type_a
|
|
35
36
|
self.type_b = type_b
|
|
37
|
+
self._cached_hash = hash((Equivalence, self.type_a, self.type_b))
|
|
36
38
|
|
|
37
39
|
def pp_str(self, mapping: dict[TypeVariable, Any]) -> str:
|
|
38
40
|
return f"{self.type_a.pp_str(mapping)} == {self.type_b.pp_str(mapping)}"
|
|
@@ -49,14 +51,15 @@ class Equivalence(TypeConstraint):
|
|
|
49
51
|
)
|
|
50
52
|
|
|
51
53
|
def __hash__(self):
|
|
52
|
-
return
|
|
54
|
+
return self._cached_hash
|
|
53
55
|
|
|
54
56
|
|
|
55
57
|
class Existence(TypeConstraint):
|
|
56
|
-
__slots__ = ("type_",)
|
|
58
|
+
__slots__ = ("type_", "_cached_hash")
|
|
57
59
|
|
|
58
60
|
def __init__(self, type_):
|
|
59
61
|
self.type_ = type_
|
|
62
|
+
self._cached_hash = hash((Existence, self.type_))
|
|
60
63
|
|
|
61
64
|
def pp_str(self, mapping: dict[TypeVariable, Any]) -> str:
|
|
62
65
|
return f"V {self.type_.pp_str(mapping)}"
|
|
@@ -68,7 +71,7 @@ class Existence(TypeConstraint):
|
|
|
68
71
|
return type(other) is Existence and self.type_ == other.type_
|
|
69
72
|
|
|
70
73
|
def __hash__(self):
|
|
71
|
-
return
|
|
74
|
+
return self._cached_hash
|
|
72
75
|
|
|
73
76
|
def replace(self, replacements):
|
|
74
77
|
if self.type_ in replacements:
|
|
@@ -84,11 +87,13 @@ class Subtype(TypeConstraint):
|
|
|
84
87
|
__slots__ = (
|
|
85
88
|
"super_type",
|
|
86
89
|
"sub_type",
|
|
90
|
+
"_cached_hash",
|
|
87
91
|
)
|
|
88
92
|
|
|
89
93
|
def __init__(self, sub_type: TypeType, super_type: TypeType):
|
|
90
94
|
self.super_type = super_type
|
|
91
95
|
self.sub_type = sub_type
|
|
96
|
+
self._cached_hash = hash((Subtype, self.sub_type, self.super_type))
|
|
92
97
|
|
|
93
98
|
def pp_str(self, mapping: dict[TypeVariable, Any]) -> str:
|
|
94
99
|
return f"{self.sub_type.pp_str(mapping)} <: {self.super_type.pp_str(mapping)}"
|
|
@@ -100,7 +105,7 @@ class Subtype(TypeConstraint):
|
|
|
100
105
|
return type(other) is Subtype and self.sub_type == other.sub_type and self.super_type == other.super_type
|
|
101
106
|
|
|
102
107
|
def __hash__(self):
|
|
103
|
-
return
|
|
108
|
+
return self._cached_hash
|
|
104
109
|
|
|
105
110
|
def replace(self, replacements):
|
|
106
111
|
subtype, supertype = None, None
|
|
@@ -139,12 +144,14 @@ class Add(TypeConstraint):
|
|
|
139
144
|
"type_0",
|
|
140
145
|
"type_1",
|
|
141
146
|
"type_r",
|
|
147
|
+
"_cached_hash",
|
|
142
148
|
)
|
|
143
149
|
|
|
144
150
|
def __init__(self, type_0, type_1, type_r):
|
|
145
151
|
self.type_0 = type_0
|
|
146
152
|
self.type_1 = type_1
|
|
147
153
|
self.type_r = type_r
|
|
154
|
+
self._cached_hash = hash((Add, self.type_0, self.type_1, self.type_r))
|
|
148
155
|
|
|
149
156
|
def pp_str(self, mapping: dict[TypeVariable, Any]) -> str:
|
|
150
157
|
return f"{self.type_r.pp_str(mapping)} == {self.type_0.pp_str(mapping)} + {self.type_1.pp_str(mapping)}"
|
|
@@ -161,7 +168,7 @@ class Add(TypeConstraint):
|
|
|
161
168
|
)
|
|
162
169
|
|
|
163
170
|
def __hash__(self):
|
|
164
|
-
return
|
|
171
|
+
return self._cached_hash
|
|
165
172
|
|
|
166
173
|
def replace(self, replacements):
|
|
167
174
|
t0, t1, tr = None, None, None
|
|
@@ -206,12 +213,14 @@ class Sub(TypeConstraint):
|
|
|
206
213
|
"type_0",
|
|
207
214
|
"type_1",
|
|
208
215
|
"type_r",
|
|
216
|
+
"_cached_hash",
|
|
209
217
|
)
|
|
210
218
|
|
|
211
219
|
def __init__(self, type_0, type_1, type_r):
|
|
212
220
|
self.type_0 = type_0
|
|
213
221
|
self.type_1 = type_1
|
|
214
222
|
self.type_r = type_r
|
|
223
|
+
self._cached_hash = hash((Sub, self.type_0, self.type_1, self.type_r))
|
|
215
224
|
|
|
216
225
|
def pp_str(self, mapping: dict[TypeVariable, Any]) -> str:
|
|
217
226
|
return f"{self.type_r.pp_str(mapping)} == {self.type_0.pp_str(mapping)} - {self.type_1.pp_str(mapping)}"
|
|
@@ -228,7 +237,7 @@ class Sub(TypeConstraint):
|
|
|
228
237
|
)
|
|
229
238
|
|
|
230
239
|
def __hash__(self):
|
|
231
|
-
return
|
|
240
|
+
return self._cached_hash
|
|
232
241
|
|
|
233
242
|
def replace(self, replacements):
|
|
234
243
|
t0, t1, tr = None, None, None
|
|
@@ -268,7 +277,7 @@ _typevariable_counter = count()
|
|
|
268
277
|
|
|
269
278
|
|
|
270
279
|
class TypeVariable:
|
|
271
|
-
__slots__ = ("idx", "name")
|
|
280
|
+
__slots__ = ("idx", "name", "_cached_hash")
|
|
272
281
|
|
|
273
282
|
def __init__(self, idx: int | None = None, name: str | None = None):
|
|
274
283
|
if idx is None:
|
|
@@ -277,6 +286,8 @@ class TypeVariable:
|
|
|
277
286
|
self.idx: int = idx
|
|
278
287
|
self.name = name
|
|
279
288
|
|
|
289
|
+
self._cached_hash = hash((TypeVariable, self.name if self.name else self.idx))
|
|
290
|
+
|
|
280
291
|
def pp_str(self, mapping: dict[TypeVariable, Any]) -> str:
|
|
281
292
|
varname = mapping.get(self, self.name)
|
|
282
293
|
if varname is None:
|
|
@@ -291,12 +302,10 @@ class TypeVariable:
|
|
|
291
302
|
return self.idx == other.idx
|
|
292
303
|
|
|
293
304
|
def _hash(self, visited=None): # pylint:disable=unused-argument
|
|
294
|
-
|
|
295
|
-
return hash((TypeVariable, self.name))
|
|
296
|
-
return hash((TypeVariable, self.idx))
|
|
305
|
+
return self._cached_hash
|
|
297
306
|
|
|
298
307
|
def __hash__(self):
|
|
299
|
-
return self.
|
|
308
|
+
return self._cached_hash
|
|
300
309
|
|
|
301
310
|
def __repr__(self):
|
|
302
311
|
if self.name:
|
|
@@ -336,6 +345,8 @@ class DerivedTypeVariable(TypeVariable):
|
|
|
336
345
|
if not self.labels:
|
|
337
346
|
raise ValueError("A DerivedTypeVariable must have at least one label")
|
|
338
347
|
|
|
348
|
+
self._cached_hash = hash((DerivedTypeVariable, self.type_var, self.labels))
|
|
349
|
+
|
|
339
350
|
def one_label(self) -> BaseLabel | None:
|
|
340
351
|
return self.labels[0] if len(self.labels) == 1 else None
|
|
341
352
|
|
|
@@ -358,10 +369,10 @@ class DerivedTypeVariable(TypeVariable):
|
|
|
358
369
|
)
|
|
359
370
|
|
|
360
371
|
def _hash(self, visited=None):
|
|
361
|
-
return
|
|
372
|
+
return self._cached_hash
|
|
362
373
|
|
|
363
374
|
def __hash__(self):
|
|
364
|
-
return self.
|
|
375
|
+
return self._cached_hash
|
|
365
376
|
|
|
366
377
|
def __repr__(self):
|
|
367
378
|
return ".".join([repr(self.type_var)] + [repr(lbl) for lbl in self.labels])
|
|
@@ -437,13 +448,16 @@ class TypeVariables:
|
|
|
437
448
|
|
|
438
449
|
|
|
439
450
|
class BaseLabel:
|
|
440
|
-
__slots__ = ()
|
|
451
|
+
__slots__ = ("_cached_hash",)
|
|
452
|
+
|
|
453
|
+
def __init__(self):
|
|
454
|
+
self._cached_hash = hash((type(self), *tuple(getattr(self, k) for k in self.__slots__ if k != "_cached_hash")))
|
|
441
455
|
|
|
442
456
|
def __eq__(self, other):
|
|
443
|
-
return type(self) is type(other) and
|
|
457
|
+
return type(self) is type(other) and self._cached_hash == other._cached_hash
|
|
444
458
|
|
|
445
459
|
def __hash__(self):
|
|
446
|
-
return
|
|
460
|
+
return self._cached_hash
|
|
447
461
|
|
|
448
462
|
@property
|
|
449
463
|
def variance(self) -> Variance:
|
|
@@ -455,6 +469,7 @@ class FuncIn(BaseLabel):
|
|
|
455
469
|
|
|
456
470
|
def __init__(self, loc):
|
|
457
471
|
self.loc = loc
|
|
472
|
+
super().__init__()
|
|
458
473
|
|
|
459
474
|
def __repr__(self):
|
|
460
475
|
return f"in<{self.loc}>"
|
|
@@ -465,6 +480,7 @@ class FuncOut(BaseLabel):
|
|
|
465
480
|
|
|
466
481
|
def __init__(self, loc):
|
|
467
482
|
self.loc = loc
|
|
483
|
+
super().__init__()
|
|
468
484
|
|
|
469
485
|
def __repr__(self):
|
|
470
486
|
return f"out<{self.loc}>"
|
|
@@ -493,6 +509,7 @@ class AddN(BaseLabel):
|
|
|
493
509
|
|
|
494
510
|
def __init__(self, n):
|
|
495
511
|
self.n = n
|
|
512
|
+
super().__init__()
|
|
496
513
|
|
|
497
514
|
def __repr__(self):
|
|
498
515
|
return "+%d" % self.n
|
|
@@ -503,6 +520,7 @@ class SubN(BaseLabel):
|
|
|
503
520
|
|
|
504
521
|
def __init__(self, n):
|
|
505
522
|
self.n = n
|
|
523
|
+
super().__init__()
|
|
506
524
|
|
|
507
525
|
def __repr__(self):
|
|
508
526
|
return "-%d" % self.n
|
|
@@ -513,6 +531,7 @@ class ConvertTo(BaseLabel):
|
|
|
513
531
|
|
|
514
532
|
def __init__(self, to_bits):
|
|
515
533
|
self.to_bits = to_bits
|
|
534
|
+
super().__init__()
|
|
516
535
|
|
|
517
536
|
def __repr__(self):
|
|
518
537
|
return "conv(%d)" % self.to_bits
|
|
@@ -527,6 +546,7 @@ class ReinterpretAs(BaseLabel):
|
|
|
527
546
|
def __init__(self, to_type, to_bits):
|
|
528
547
|
self.to_type = to_type
|
|
529
548
|
self.to_bits = to_bits
|
|
549
|
+
super().__init__()
|
|
530
550
|
|
|
531
551
|
def __repr__(self):
|
|
532
552
|
return f"reinterpret({self.to_type}{self.to_bits})"
|
|
@@ -541,6 +561,7 @@ class HasField(BaseLabel):
|
|
|
541
561
|
def __init__(self, bits, offset):
|
|
542
562
|
self.bits = bits
|
|
543
563
|
self.offset = offset
|
|
564
|
+
super().__init__()
|
|
544
565
|
|
|
545
566
|
def __repr__(self):
|
|
546
567
|
if self.bits == MAX_POINTSTO_BITS:
|
angr/angrdb/db.py
CHANGED
|
@@ -43,7 +43,7 @@ class AngrDB:
|
|
|
43
43
|
except DatabaseError as ex:
|
|
44
44
|
raise AngrCorruptDBError("The target file may not be an angr database or it is corrupted.") from ex
|
|
45
45
|
except Exception as ex:
|
|
46
|
-
raise AngrDBError
|
|
46
|
+
raise AngrDBError from ex
|
|
47
47
|
|
|
48
48
|
@staticmethod
|
|
49
49
|
@contextmanager
|
angr/block.py
CHANGED
|
@@ -142,6 +142,7 @@ class Block(Serializable):
|
|
|
142
142
|
"_strict_block_end",
|
|
143
143
|
"_cross_insn_opt",
|
|
144
144
|
"_load_from_ro_regions",
|
|
145
|
+
"_const_prop",
|
|
145
146
|
"_initial_regs",
|
|
146
147
|
]
|
|
147
148
|
|
|
@@ -164,6 +165,7 @@ class Block(Serializable):
|
|
|
164
165
|
collect_data_refs=False,
|
|
165
166
|
cross_insn_opt=True,
|
|
166
167
|
load_from_ro_regions=False,
|
|
168
|
+
const_prop=False,
|
|
167
169
|
initial_regs=None,
|
|
168
170
|
skip_stmts=False,
|
|
169
171
|
):
|
|
@@ -191,7 +193,9 @@ class Block(Serializable):
|
|
|
191
193
|
self.thumb = thumb
|
|
192
194
|
self.addr = addr
|
|
193
195
|
self._opt_level = opt_level
|
|
194
|
-
self._initial_regs: list[tuple[int, int, int]] | None =
|
|
196
|
+
self._initial_regs: list[tuple[int, int, int]] | None = (
|
|
197
|
+
initial_regs if (collect_data_refs or const_prop) else None
|
|
198
|
+
)
|
|
195
199
|
|
|
196
200
|
if self._project is None and byte_string is None:
|
|
197
201
|
raise ValueError('"byte_string" has to be specified if "project" is not provided.')
|
|
@@ -218,6 +222,7 @@ class Block(Serializable):
|
|
|
218
222
|
strict_block_end=strict_block_end,
|
|
219
223
|
collect_data_refs=collect_data_refs,
|
|
220
224
|
load_from_ro_regions=load_from_ro_regions,
|
|
225
|
+
const_prop=const_prop,
|
|
221
226
|
cross_insn_opt=cross_insn_opt,
|
|
222
227
|
skip_stmts=skip_stmts,
|
|
223
228
|
)
|
|
@@ -238,6 +243,7 @@ class Block(Serializable):
|
|
|
238
243
|
self._strict_block_end = strict_block_end
|
|
239
244
|
self._cross_insn_opt = cross_insn_opt
|
|
240
245
|
self._load_from_ro_regions = load_from_ro_regions
|
|
246
|
+
self._const_prop = const_prop
|
|
241
247
|
|
|
242
248
|
self._instructions = num_inst
|
|
243
249
|
self._instruction_addrs: list[int] = []
|
|
@@ -342,6 +348,7 @@ class Block(Serializable):
|
|
|
342
348
|
strict_block_end=self._strict_block_end,
|
|
343
349
|
cross_insn_opt=self._cross_insn_opt,
|
|
344
350
|
load_from_ro_regions=self._load_from_ro_regions,
|
|
351
|
+
const_prop=self._const_prop,
|
|
345
352
|
)
|
|
346
353
|
if self._initial_regs:
|
|
347
354
|
self.reset_initial_regs()
|
|
@@ -373,6 +380,7 @@ class Block(Serializable):
|
|
|
373
380
|
strict_block_end=self._strict_block_end,
|
|
374
381
|
cross_insn_opt=self._cross_insn_opt,
|
|
375
382
|
load_from_ro_regions=self._load_from_ro_regions,
|
|
383
|
+
const_prop=self._const_prop,
|
|
376
384
|
)
|
|
377
385
|
if self._initial_regs:
|
|
378
386
|
self.reset_initial_regs()
|
angr/calling_conventions.py
CHANGED
|
@@ -69,7 +69,7 @@ class AllocHelper:
|
|
|
69
69
|
val.struct, {field: self.translate(subval, base) for field, subval in val._values.items()}
|
|
70
70
|
)
|
|
71
71
|
if isinstance(val, claripy.ast.Bits):
|
|
72
|
-
return
|
|
72
|
+
return claripy.replace(val, self.base, base)
|
|
73
73
|
if type(val) is list:
|
|
74
74
|
return [self.translate(subval, base) for subval in val]
|
|
75
75
|
raise TypeError(type(val))
|
angr/engines/engine.py
CHANGED
|
@@ -4,10 +4,16 @@ from __future__ import annotations
|
|
|
4
4
|
import abc
|
|
5
5
|
import logging
|
|
6
6
|
import threading
|
|
7
|
-
import angr
|
|
8
7
|
|
|
9
8
|
from archinfo.arch_soot import SootAddressDescriptor
|
|
10
9
|
|
|
10
|
+
import angr
|
|
11
|
+
from angr import sim_options as o
|
|
12
|
+
from angr.errors import SimException
|
|
13
|
+
from angr.state_plugins.inspect import BP_AFTER, BP_BEFORE
|
|
14
|
+
|
|
15
|
+
from .successors import SimSuccessors
|
|
16
|
+
|
|
11
17
|
l = logging.getLogger(name=__name__)
|
|
12
18
|
|
|
13
19
|
|
|
@@ -32,12 +38,6 @@ class SimEngineBase:
|
|
|
32
38
|
self.project = state[0]
|
|
33
39
|
self.state = None
|
|
34
40
|
|
|
35
|
-
def _is_true(self, v):
|
|
36
|
-
return v is True
|
|
37
|
-
|
|
38
|
-
def _is_false(self, v):
|
|
39
|
-
return v is False
|
|
40
|
-
|
|
41
41
|
|
|
42
42
|
class SimEngine(SimEngineBase, metaclass=abc.ABCMeta):
|
|
43
43
|
"""
|
|
@@ -183,7 +183,7 @@ class SuccessorsMixin(SimEngine):
|
|
|
183
183
|
|
|
184
184
|
return self.successors
|
|
185
185
|
|
|
186
|
-
def process_successors(self, successors, **kwargs):
|
|
186
|
+
def process_successors(self, successors, **kwargs): # pylint:disable=unused-argument
|
|
187
187
|
"""
|
|
188
188
|
Implement this function to fill out the SimSuccessors object with the results of stepping state.
|
|
189
189
|
|
|
@@ -201,10 +201,3 @@ class SuccessorsMixin(SimEngine):
|
|
|
201
201
|
:param kwargs: Any extra arguments. Do not fail if you are passed unexpected arguments.
|
|
202
202
|
"""
|
|
203
203
|
successors.processed = False # mark failure
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
# pylint:disable=wrong-import-position
|
|
207
|
-
from angr import sim_options as o
|
|
208
|
-
from angr.state_plugins.inspect import BP_BEFORE, BP_AFTER
|
|
209
|
-
from .successors import SimSuccessors
|
|
210
|
-
from angr.errors import SimException
|
angr/engines/pcode/lifter.py
CHANGED
|
@@ -122,6 +122,7 @@ class IRSB:
|
|
|
122
122
|
"arch",
|
|
123
123
|
"behaviors",
|
|
124
124
|
"data_refs",
|
|
125
|
+
"const_vals",
|
|
125
126
|
"default_exit_target",
|
|
126
127
|
"jumpkind",
|
|
127
128
|
"next",
|
|
@@ -138,6 +139,7 @@ class IRSB:
|
|
|
138
139
|
arch: archinfo.Arch
|
|
139
140
|
behaviors: BehaviorFactory | None
|
|
140
141
|
data_refs: Sequence # Note: currently unused
|
|
142
|
+
const_vals: Sequence # Note: currently unused
|
|
141
143
|
default_exit_target: Optional # Note: currently used
|
|
142
144
|
jumpkind: str | None
|
|
143
145
|
next: int | None
|
|
@@ -204,6 +206,7 @@ class IRSB:
|
|
|
204
206
|
self.arch = arch
|
|
205
207
|
self.behaviors = None
|
|
206
208
|
self.data_refs = ()
|
|
209
|
+
self.const_vals = ()
|
|
207
210
|
self.default_exit_target = None
|
|
208
211
|
self.jumpkind = None
|
|
209
212
|
self.next = None
|
|
@@ -1043,6 +1046,7 @@ class PcodeLifterEngineMixin(SimEngineBase):
|
|
|
1043
1046
|
collect_data_refs: bool = False,
|
|
1044
1047
|
load_from_ro_regions: bool = False,
|
|
1045
1048
|
cross_insn_opt: bool | None = None,
|
|
1049
|
+
const_prop: bool | None = None,
|
|
1046
1050
|
):
|
|
1047
1051
|
"""
|
|
1048
1052
|
Temporary compatibility interface for integration with block code.
|
|
@@ -1064,6 +1068,7 @@ class PcodeLifterEngineMixin(SimEngineBase):
|
|
|
1064
1068
|
collect_data_refs,
|
|
1065
1069
|
load_from_ro_regions,
|
|
1066
1070
|
cross_insn_opt,
|
|
1071
|
+
const_prop,
|
|
1067
1072
|
)
|
|
1068
1073
|
|
|
1069
1074
|
def lift_pcode(
|
|
@@ -1084,6 +1089,7 @@ class PcodeLifterEngineMixin(SimEngineBase):
|
|
|
1084
1089
|
collect_data_refs: bool = False,
|
|
1085
1090
|
load_from_ro_regions: bool = False,
|
|
1086
1091
|
cross_insn_opt: bool | None = None,
|
|
1092
|
+
const_prop: bool | None = None,
|
|
1087
1093
|
):
|
|
1088
1094
|
"""
|
|
1089
1095
|
Lift an IRSB.
|
|
@@ -1111,6 +1117,8 @@ class PcodeLifterEngineMixin(SimEngineBase):
|
|
|
1111
1117
|
"""
|
|
1112
1118
|
if cross_insn_opt:
|
|
1113
1119
|
l.debug("cross_insn_opt is ignored for p-code lifter")
|
|
1120
|
+
if const_prop:
|
|
1121
|
+
l.debug("const_prop is ignored for p-code lifter")
|
|
1114
1122
|
if load_from_ro_regions:
|
|
1115
1123
|
l.debug("load_from_ro_regions is ignored for p-code lifter")
|
|
1116
1124
|
|
angr/engines/successors.py
CHANGED
|
@@ -356,7 +356,7 @@ class SimSuccessors:
|
|
|
356
356
|
if o.KEEP_IP_SYMBOLIC in split_state.options:
|
|
357
357
|
split_state.regs.ip = target
|
|
358
358
|
else:
|
|
359
|
-
split_state.add_constraints(cond
|
|
359
|
+
split_state.add_constraints(cond)
|
|
360
360
|
split_state.regs.ip = a
|
|
361
361
|
if split_state.supports_inspect:
|
|
362
362
|
split_state.inspect.downsize()
|
|
@@ -43,7 +43,7 @@ def boolean_extend(O, a, b, size):
|
|
|
43
43
|
def op_concretize(op):
|
|
44
44
|
if type(op) is int:
|
|
45
45
|
return op
|
|
46
|
-
op_e = op
|
|
46
|
+
op_e = claripy.excavate_ite(op)
|
|
47
47
|
if op_e.op == "If":
|
|
48
48
|
cases = list(claripy.reverse_ite_cases(op_e))
|
|
49
49
|
if all(c.op == "BVV" for _, c in cases):
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
import logging
|
|
3
4
|
|
|
4
5
|
import claripy
|
|
5
6
|
import pyvex
|
|
6
7
|
|
|
7
|
-
from . import irop
|
|
8
|
-
from . import ccall
|
|
9
|
-
from angr.engines.vex.light import VEXMixin
|
|
10
8
|
from angr import errors
|
|
11
9
|
from angr import sim_options as o
|
|
10
|
+
from angr.engines.vex.light import VEXMixin
|
|
11
|
+
|
|
12
|
+
from . import ccall, irop
|
|
12
13
|
|
|
13
14
|
l = logging.getLogger(__name__)
|
|
14
15
|
zero = claripy.BVV(0, 32)
|
|
@@ -39,13 +40,8 @@ class ClaripyDataMixin(VEXMixin):
|
|
|
39
40
|
|
|
40
41
|
# util methods
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def _is_false(self, v):
|
|
46
|
-
return claripy.is_false(v)
|
|
47
|
-
|
|
48
|
-
def _optimize_guarded_addr(self, addr, guard):
|
|
43
|
+
@staticmethod
|
|
44
|
+
def _optimize_guarded_addr(addr, guard):
|
|
49
45
|
# optimization: is the guard the same as the condition inside the address? if so, unpack the address and remove
|
|
50
46
|
# the guarding condition.
|
|
51
47
|
if (
|
|
@@ -65,6 +61,7 @@ class ClaripyDataMixin(VEXMixin):
|
|
|
65
61
|
|
|
66
62
|
# statements
|
|
67
63
|
|
|
64
|
+
# pylint: disable=too-many-positional-arguments
|
|
68
65
|
def _perform_vex_stmt_LoadG(self, addr, alt, guard, dst, cvt, end):
|
|
69
66
|
addr = self._optimize_guarded_addr(addr, guard)
|
|
70
67
|
super()._perform_vex_stmt_LoadG(addr, alt, guard, dst, cvt, end)
|