angr 9.2.174__cp310-abi3-macosx_11_0_arm64.whl → 9.2.176__cp310-abi3-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/__main__.py +32 -2
- angr/analyses/calling_convention/calling_convention.py +12 -0
- angr/analyses/cfg/cfg_base.py +1 -1
- angr/analyses/cfg/cfg_fast.py +27 -8
- angr/analyses/complete_calling_conventions.py +39 -26
- angr/analyses/decompiler/ail_simplifier.py +13 -11
- angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +5 -1
- angr/analyses/decompiler/clinic.py +54 -40
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +3 -3
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/__init__.py +4 -4
- angr/analyses/decompiler/peephole_optimizations/{inlined_wstrcpy.py → inlined_wcscpy.py} +16 -8
- angr/analyses/decompiler/peephole_optimizations/{inlined_wstrcpy_consolidation.py → inlined_wcscpy_consolidation.py} +13 -13
- angr/analyses/decompiler/ssailification/rewriting_engine.py +14 -1
- angr/analyses/decompiler/structured_codegen/c.py +6 -5
- angr/analyses/decompiler/structuring/dream.py +2 -2
- angr/analyses/decompiler/structuring/phoenix.py +101 -23
- angr/analyses/decompiler/utils.py +1 -1
- angr/analyses/smc.py +1 -1
- angr/analyses/stack_pointer_tracker.py +4 -3
- angr/analyses/typehoon/lifter.py +29 -18
- angr/analyses/typehoon/simple_solver.py +157 -50
- angr/analyses/typehoon/translator.py +34 -34
- angr/analyses/typehoon/typeconsts.py +33 -15
- angr/analyses/typehoon/typevars.py +9 -2
- angr/analyses/variable_recovery/engine_ail.py +4 -2
- angr/analyses/variable_recovery/engine_base.py +4 -1
- angr/analyses/variable_recovery/variable_recovery_fast.py +3 -1
- angr/calling_conventions.py +2 -1
- angr/engines/icicle.py +4 -4
- angr/engines/vex/claripy/ccall.py +3 -3
- angr/knowledge_plugins/functions/function.py +18 -1
- angr/misc/bug_report.py +11 -2
- angr/procedures/definitions/__init__.py +88 -20
- angr/procedures/definitions/common/glibc.json +3516 -0
- angr/procedures/definitions/parse_glibc.py +78 -0
- angr/procedures/libc/fgets.py +2 -1
- angr/procedures/posix/pthread.py +4 -4
- angr/procedures/stubs/format_parser.py +3 -3
- angr/rustylib.abi3.so +0 -0
- angr/sim_type.py +73 -11
- angr/simos/windows.py +1 -1
- angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +1 -1
- angr/unicornlib.dylib +0 -0
- angr/utils/constants.py +1 -1
- angr/utils/library.py +1 -0
- angr/utils/strings.py +20 -0
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/METADATA +5 -5
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/RECORD +54 -52
- angr/procedures/definitions/glibc.py +0 -8372
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/WHEEL +0 -0
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/entry_points.txt +0 -0
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.174.dist-info → angr-9.2.176.dist-info}/top_level.txt +0 -0
|
@@ -5,6 +5,7 @@ All type constants used in type inference. They can be mapped, translated, or re
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
import functools
|
|
8
|
+
import itertools
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
def memoize(f):
|
|
@@ -24,6 +25,9 @@ def memoize(f):
|
|
|
24
25
|
class TypeConstant:
|
|
25
26
|
SIZE = None
|
|
26
27
|
|
|
28
|
+
def __init__(self, name: str | None = None):
|
|
29
|
+
self.name = name
|
|
30
|
+
|
|
27
31
|
def pp_str(self, mapping) -> str: # pylint:disable=unused-argument
|
|
28
32
|
return repr(self)
|
|
29
33
|
|
|
@@ -115,7 +119,8 @@ class Int512(Int):
|
|
|
115
119
|
|
|
116
120
|
|
|
117
121
|
class IntVar(Int):
|
|
118
|
-
def __init__(self, size):
|
|
122
|
+
def __init__(self, size, name: str | None = None):
|
|
123
|
+
super().__init__(name)
|
|
119
124
|
self._size = size
|
|
120
125
|
|
|
121
126
|
@property
|
|
@@ -146,7 +151,8 @@ class Float64(Float):
|
|
|
146
151
|
|
|
147
152
|
|
|
148
153
|
class Pointer(TypeConstant):
|
|
149
|
-
def __init__(self, basetype: TypeConstant | None):
|
|
154
|
+
def __init__(self, basetype: TypeConstant | None, name: str | None = None):
|
|
155
|
+
super().__init__(name=name)
|
|
150
156
|
self.basetype: TypeConstant | None = basetype
|
|
151
157
|
|
|
152
158
|
def __eq__(self, other):
|
|
@@ -169,13 +175,15 @@ class Pointer32(Pointer, Int32):
|
|
|
169
175
|
32-bit pointers.
|
|
170
176
|
"""
|
|
171
177
|
|
|
172
|
-
def __init__(self, basetype=None):
|
|
173
|
-
Pointer.__init__(self, basetype)
|
|
178
|
+
def __init__(self, basetype=None, name: str | None = None):
|
|
179
|
+
Pointer.__init__(self, basetype, name=name)
|
|
180
|
+
Int32.__init__(self, name=name)
|
|
174
181
|
|
|
175
182
|
@memoize
|
|
176
183
|
def __repr__(self, memo=None):
|
|
177
184
|
bt = self.basetype.__repr__(memo=memo) if isinstance(self.basetype, TypeConstant) else repr(self.basetype)
|
|
178
|
-
|
|
185
|
+
name_str = f"{self.name}#" if self.name else ""
|
|
186
|
+
return f"{name_str}ptr32({bt})"
|
|
179
187
|
|
|
180
188
|
|
|
181
189
|
class Pointer64(Pointer, Int64):
|
|
@@ -183,17 +191,20 @@ class Pointer64(Pointer, Int64):
|
|
|
183
191
|
64-bit pointers.
|
|
184
192
|
"""
|
|
185
193
|
|
|
186
|
-
def __init__(self, basetype=None):
|
|
187
|
-
Pointer.__init__(self, basetype)
|
|
194
|
+
def __init__(self, basetype=None, name: str | None = None):
|
|
195
|
+
Pointer.__init__(self, basetype, name=name)
|
|
196
|
+
Int64.__init__(self, name=name)
|
|
188
197
|
|
|
189
198
|
@memoize
|
|
190
199
|
def __repr__(self, memo=None):
|
|
191
200
|
bt = self.basetype.__repr__(memo=memo) if isinstance(self.basetype, TypeConstant) else repr(self.basetype)
|
|
192
|
-
|
|
201
|
+
name_str = f"{self.name}#" if self.name else ""
|
|
202
|
+
return f"{name_str}ptr64({bt})"
|
|
193
203
|
|
|
194
204
|
|
|
195
205
|
class Array(TypeConstant):
|
|
196
|
-
def __init__(self, element=None, count=None):
|
|
206
|
+
def __init__(self, element=None, count=None, name: str | None = None):
|
|
207
|
+
super().__init__(name=name)
|
|
197
208
|
self.element: TypeConstant | None = element
|
|
198
209
|
self.count: int | None = count
|
|
199
210
|
|
|
@@ -222,18 +233,22 @@ class Array(TypeConstant):
|
|
|
222
233
|
return self._hash(set())
|
|
223
234
|
|
|
224
235
|
|
|
236
|
+
_STRUCT_ID = itertools.count()
|
|
237
|
+
|
|
238
|
+
|
|
225
239
|
class Struct(TypeConstant):
|
|
226
|
-
def __init__(self, fields=None, name=None, field_names=None, is_cppclass: bool = False):
|
|
240
|
+
def __init__(self, fields=None, name=None, field_names=None, is_cppclass: bool = False, idx: int = -1):
|
|
241
|
+
super().__init__(name=name)
|
|
227
242
|
self.fields = {} if fields is None else fields # offset to type
|
|
228
|
-
self.name = name
|
|
229
243
|
self.field_names = field_names
|
|
230
244
|
self.is_cppclass = is_cppclass
|
|
245
|
+
self.idx = idx if idx != -1 else next(_STRUCT_ID)
|
|
231
246
|
|
|
232
247
|
def _hash(self, visited: set[int]):
|
|
233
248
|
if id(self) in visited:
|
|
234
249
|
return 0
|
|
235
250
|
visited.add(id(self))
|
|
236
|
-
return hash((type(self), self._hash_fields(visited)))
|
|
251
|
+
return hash((type(self), self.idx, self._hash_fields(visited)))
|
|
237
252
|
|
|
238
253
|
def _hash_fields(self, visited: set[int]):
|
|
239
254
|
keys = sorted(self.fields.keys())
|
|
@@ -252,6 +267,7 @@ class Struct(TypeConstant):
|
|
|
252
267
|
@memoize
|
|
253
268
|
def __repr__(self, memo=None):
|
|
254
269
|
prefix = "CppClass" if self.is_cppclass else "struct"
|
|
270
|
+
prefix += f"#{self.idx}"
|
|
255
271
|
if self.name:
|
|
256
272
|
prefix = f"{prefix} {self.name}"
|
|
257
273
|
return (
|
|
@@ -262,14 +278,15 @@ class Struct(TypeConstant):
|
|
|
262
278
|
)
|
|
263
279
|
|
|
264
280
|
def __eq__(self, other):
|
|
265
|
-
return type(other) is type(self) and hash(self) == hash(other)
|
|
281
|
+
return type(other) is type(self) and self.idx == other.idx and hash(self) == hash(other)
|
|
266
282
|
|
|
267
283
|
def __hash__(self):
|
|
268
284
|
return self._hash(set())
|
|
269
285
|
|
|
270
286
|
|
|
271
287
|
class Function(TypeConstant):
|
|
272
|
-
def __init__(self, params: list, outputs: list):
|
|
288
|
+
def __init__(self, params: list, outputs: list, name: str | None = None):
|
|
289
|
+
super().__init__(name=name)
|
|
273
290
|
self.params = params
|
|
274
291
|
self.outputs = outputs
|
|
275
292
|
|
|
@@ -298,7 +315,8 @@ class Function(TypeConstant):
|
|
|
298
315
|
|
|
299
316
|
|
|
300
317
|
class TypeVariableReference(TypeConstant):
|
|
301
|
-
def __init__(self, typevar):
|
|
318
|
+
def __init__(self, typevar, name: str | None = None):
|
|
319
|
+
super().__init__(name=name)
|
|
302
320
|
self.typevar = typevar
|
|
303
321
|
|
|
304
322
|
def __repr__(self, memo=None):
|
|
@@ -559,20 +559,27 @@ class ReinterpretAs(BaseLabel):
|
|
|
559
559
|
|
|
560
560
|
|
|
561
561
|
class HasField(BaseLabel):
|
|
562
|
+
"""
|
|
563
|
+
Has a field of the given bit size * elem_count at the given offset.
|
|
564
|
+
"""
|
|
565
|
+
|
|
562
566
|
__slots__ = (
|
|
563
567
|
"bits",
|
|
568
|
+
"elem_count",
|
|
564
569
|
"offset",
|
|
565
570
|
)
|
|
566
571
|
|
|
567
|
-
def __init__(self, bits, offset):
|
|
572
|
+
def __init__(self, bits, offset, elem_count: int = 1):
|
|
568
573
|
self.bits = bits
|
|
569
574
|
self.offset = offset
|
|
575
|
+
self.elem_count = elem_count
|
|
570
576
|
super().__init__()
|
|
571
577
|
|
|
572
578
|
def __repr__(self):
|
|
573
579
|
if self.bits == MAX_POINTSTO_BITS:
|
|
574
580
|
return f"<MAX_POINTSTO_BITS>@{self.offset}"
|
|
575
|
-
|
|
581
|
+
elem_str = str(self.elem_count) if self.elem_count != 1 else ""
|
|
582
|
+
return f"<{self.bits} bits>@{self.offset}{elem_str}"
|
|
576
583
|
|
|
577
584
|
|
|
578
585
|
class IsArray(BaseLabel):
|
|
@@ -34,6 +34,7 @@ class SimEngineVRAIL(
|
|
|
34
34
|
def __init__(
|
|
35
35
|
self,
|
|
36
36
|
*args,
|
|
37
|
+
type_lifter: TypeLifter,
|
|
37
38
|
call_info=None,
|
|
38
39
|
vvar_to_vvar: dict[int, int] | None,
|
|
39
40
|
vvar_type_hints: dict[int, typeconsts.TypeConstant] | None = None,
|
|
@@ -44,6 +45,7 @@ class SimEngineVRAIL(
|
|
|
44
45
|
self._reference_spoffset: bool = False
|
|
45
46
|
self.call_info = call_info or {}
|
|
46
47
|
self.vvar_to_vvar = vvar_to_vvar
|
|
48
|
+
self.type_lifter = type_lifter
|
|
47
49
|
|
|
48
50
|
def _mapped_vvarid(self, vvar_id: int) -> int | None:
|
|
49
51
|
if self.vvar_to_vvar is not None and vvar_id in self.vvar_to_vvar:
|
|
@@ -195,7 +197,7 @@ class SimEngineVRAIL(
|
|
|
195
197
|
arg_type = (
|
|
196
198
|
dereference_simtype_by_lib(arg_type, prototype_libname) if prototype_libname else arg_type
|
|
197
199
|
)
|
|
198
|
-
arg_ty =
|
|
200
|
+
arg_ty = self.type_lifter.lift(arg_type)
|
|
199
201
|
type_constraint = typevars.Subtype(arg.typevar, arg_ty)
|
|
200
202
|
self.state.add_type_constraint(type_constraint)
|
|
201
203
|
|
|
@@ -282,7 +284,7 @@ class SimEngineVRAIL(
|
|
|
282
284
|
arg_type = (
|
|
283
285
|
dereference_simtype_by_lib(arg_type, prototype_libname) if prototype_libname else arg_type
|
|
284
286
|
)
|
|
285
|
-
arg_ty =
|
|
287
|
+
arg_ty = self.type_lifter.lift(arg_type)
|
|
286
288
|
if arg.typevar is not None and isinstance(
|
|
287
289
|
arg_ty, (typeconsts.TypeConstant, typevars.TypeVariable, typevars.DerivedTypeVariable)
|
|
288
290
|
):
|
|
@@ -277,7 +277,10 @@ class SimEngineVRBase(
|
|
|
277
277
|
variable, _ = existing_vars[0]
|
|
278
278
|
|
|
279
279
|
if not self.state.typevars.has_type_variable_for(variable):
|
|
280
|
-
|
|
280
|
+
if isinstance(variable, SimStackVariable) and variable.offset in self.state.stack_offset_typevars:
|
|
281
|
+
variable_typevar = self.state.stack_offset_typevars[variable.offset]
|
|
282
|
+
else:
|
|
283
|
+
variable_typevar = typevars.TypeVariable()
|
|
281
284
|
self.state.typevars.add_type_variable(variable, variable_typevar)
|
|
282
285
|
# we do not add any type constraint here because we are not sure if the given memory address will ever be
|
|
283
286
|
# accessed or not
|
|
@@ -284,6 +284,7 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
284
284
|
self._unify_variables = unify_variables
|
|
285
285
|
|
|
286
286
|
# handle type hints
|
|
287
|
+
self.type_lifter = TypeLifter(self.project.arch.bits)
|
|
287
288
|
self.vvar_type_hints = {}
|
|
288
289
|
if type_hints:
|
|
289
290
|
self._parse_type_hints(type_hints)
|
|
@@ -294,6 +295,7 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
294
295
|
call_info=call_info,
|
|
295
296
|
vvar_to_vvar=self.vvar_to_vvar,
|
|
296
297
|
vvar_type_hints=self.vvar_type_hints,
|
|
298
|
+
type_lifter=self.type_lifter,
|
|
297
299
|
)
|
|
298
300
|
self._vex_engine: SimEngineVRVEX = SimEngineVRVEX(self.project, self.kb, call_info=call_info)
|
|
299
301
|
|
|
@@ -654,7 +656,7 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
654
656
|
if ty is None:
|
|
655
657
|
return None
|
|
656
658
|
ty = ty.with_arch(self.project.arch)
|
|
657
|
-
lifted =
|
|
659
|
+
lifted = self.type_lifter.lift(ty)
|
|
658
660
|
return None if isinstance(lifted, (BottomType, TopType)) else lifted
|
|
659
661
|
|
|
660
662
|
|
angr/calling_conventions.py
CHANGED
|
@@ -34,6 +34,7 @@ from .sim_type import (
|
|
|
34
34
|
SimTypeBottom,
|
|
35
35
|
parse_signature,
|
|
36
36
|
SimTypeReference,
|
|
37
|
+
SimTypeRef,
|
|
37
38
|
)
|
|
38
39
|
from .state_plugins.sim_action_object import SimActionObject
|
|
39
40
|
|
|
@@ -1430,7 +1431,7 @@ class SimCCMicrosoftAMD64(SimCC):
|
|
|
1430
1431
|
return SimReferenceArgument(int_loc, referenced_loc)
|
|
1431
1432
|
|
|
1432
1433
|
def return_in_implicit_outparam(self, ty):
|
|
1433
|
-
if isinstance(ty, SimTypeBottom):
|
|
1434
|
+
if isinstance(ty, (SimTypeBottom, SimTypeRef)):
|
|
1434
1435
|
return False
|
|
1435
1436
|
return not isinstance(ty, SimTypeFloat) and ty.size > self.STRUCT_RETURN_THRESHOLD
|
|
1436
1437
|
|
angr/engines/icicle.py
CHANGED
|
@@ -8,7 +8,7 @@ from dataclasses import dataclass
|
|
|
8
8
|
from typing_extensions import override
|
|
9
9
|
|
|
10
10
|
import pypcode
|
|
11
|
-
from archinfo import Arch, Endness
|
|
11
|
+
from archinfo import Arch, Endness, ArchARMCortexM
|
|
12
12
|
|
|
13
13
|
from angr.engines.concrete import ConcreteEngine, HeavyConcreteState
|
|
14
14
|
from angr.engines.failure import SimEngineFailure
|
|
@@ -84,11 +84,11 @@ class IcicleEngine(ConcreteEngine):
|
|
|
84
84
|
return icicle_arch.startswith(("arm", "thumb"))
|
|
85
85
|
|
|
86
86
|
@staticmethod
|
|
87
|
-
def __is_thumb(icicle_arch: str, addr: int) -> bool:
|
|
87
|
+
def __is_thumb(angr_arch: Arch, icicle_arch: str, addr: int) -> bool:
|
|
88
88
|
"""
|
|
89
89
|
Check if the architecture is thumb based on the address.
|
|
90
90
|
"""
|
|
91
|
-
return IcicleEngine.__is_arm(icicle_arch) and addr & 1 == 1
|
|
91
|
+
return isinstance(angr_arch, ArchARMCortexM) or (IcicleEngine.__is_arm(icicle_arch) and addr & 1 == 1)
|
|
92
92
|
|
|
93
93
|
@staticmethod
|
|
94
94
|
def __get_pages(state: HeavyConcreteState) -> set[int]:
|
|
@@ -138,7 +138,7 @@ class IcicleEngine(ConcreteEngine):
|
|
|
138
138
|
log.debug("Register %s not found in icicle", register)
|
|
139
139
|
|
|
140
140
|
# Unset the thumb bit if necessary
|
|
141
|
-
if IcicleEngine.__is_thumb(icicle_arch, state.addr):
|
|
141
|
+
if IcicleEngine.__is_thumb(state.arch, icicle_arch, state.addr):
|
|
142
142
|
emu.pc = state.addr & ~1
|
|
143
143
|
emu.isa_mode = 1
|
|
144
144
|
elif "arm" in icicle_arch: # Hack to work around us calling it r15t
|
|
@@ -343,7 +343,7 @@ def pc_make_rdata_if_necessary(nbits, cf, pf, af, zf, sf, of, platform=None):
|
|
|
343
343
|
|
|
344
344
|
|
|
345
345
|
def pc_actions_ADD(state, nbits, arg_l, arg_r, cc_ndep, platform=None):
|
|
346
|
-
data_mask,
|
|
346
|
+
data_mask, _sign_mask = pc_preamble(nbits)
|
|
347
347
|
res = arg_l + arg_r
|
|
348
348
|
|
|
349
349
|
cf = claripy.If(claripy.ULT(res, arg_l), claripy.BVV(1, 1), claripy.BVV(0, 1))
|
|
@@ -701,7 +701,7 @@ def pc_calculate_rdata_all(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=Non
|
|
|
701
701
|
def pc_calculate_condition(state, cond, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=None):
|
|
702
702
|
rdata_all = pc_calculate_rdata_all_WRK(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=platform)
|
|
703
703
|
if isinstance(rdata_all, tuple):
|
|
704
|
-
cf, pf,
|
|
704
|
+
cf, pf, _af, zf, sf, of = rdata_all
|
|
705
705
|
v = op_concretize(cond)
|
|
706
706
|
|
|
707
707
|
inv = v & 1
|
|
@@ -993,7 +993,7 @@ def pc_calculate_rdata_c(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=None)
|
|
|
993
993
|
rdata_all = pc_calculate_rdata_all_WRK(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=platform)
|
|
994
994
|
|
|
995
995
|
if isinstance(rdata_all, tuple):
|
|
996
|
-
cf,
|
|
996
|
+
cf, _pf, _af, _zf, _sf, _of = rdata_all
|
|
997
997
|
return claripy.Concat(claripy.BVV(0, data[platform]["size"] - 1), cf & 1)
|
|
998
998
|
return claripy.LShR(rdata_all, data[platform]["CondBitOffsets"]["G_CC_SHIFT_C"]) & 1
|
|
999
999
|
|
|
@@ -1663,7 +1663,7 @@ class Function(Serializable):
|
|
|
1663
1663
|
|
|
1664
1664
|
@property
|
|
1665
1665
|
def demangled_name(self):
|
|
1666
|
-
ast = pydemumble.demangle(self.name)
|
|
1666
|
+
ast = pydemumble.demangle(self.name).strip()
|
|
1667
1667
|
if self.is_rust_function():
|
|
1668
1668
|
nodes = ast.split("::")[:-1]
|
|
1669
1669
|
ast = "::".join([Function._rust_fmt_node(node) for node in nodes])
|
|
@@ -1750,6 +1750,23 @@ class Function(Serializable):
|
|
|
1750
1750
|
_find_called(self.addr)
|
|
1751
1751
|
return {self._function_manager.function(a) for a in called}
|
|
1752
1752
|
|
|
1753
|
+
def holes(self, min_size: int = 8) -> int:
|
|
1754
|
+
"""
|
|
1755
|
+
Find the number of non-consecutive areas in the function that are at least `min_size` bytes large.
|
|
1756
|
+
"""
|
|
1757
|
+
|
|
1758
|
+
block_addrs = sorted(self._local_block_addrs)
|
|
1759
|
+
if not block_addrs:
|
|
1760
|
+
return 0
|
|
1761
|
+
holes = 0
|
|
1762
|
+
for i, addr in enumerate(block_addrs):
|
|
1763
|
+
if i == len(block_addrs) - 1:
|
|
1764
|
+
break
|
|
1765
|
+
next_addr = block_addrs[i + 1]
|
|
1766
|
+
if next_addr > addr + self._block_sizes[addr] and next_addr - (addr + self._block_sizes[addr]) >= min_size:
|
|
1767
|
+
holes += 1
|
|
1768
|
+
return holes
|
|
1769
|
+
|
|
1753
1770
|
def copy(self):
|
|
1754
1771
|
func = Function(self._function_manager, self.addr, name=self.name, syscall=self.is_syscall)
|
|
1755
1772
|
func.transition_graph = networkx.DiGraph(self.transition_graph)
|
angr/misc/bug_report.py
CHANGED
|
@@ -17,11 +17,20 @@ except ImportError:
|
|
|
17
17
|
print("If you install gitpython (`pip install gitpython`), I can give you git info too!")
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
angr_modules = [
|
|
20
|
+
angr_modules = [
|
|
21
|
+
"angr",
|
|
22
|
+
"archinfo",
|
|
23
|
+
"claripy",
|
|
24
|
+
"cle",
|
|
25
|
+
"pypcode",
|
|
26
|
+
"pyvex",
|
|
27
|
+
"unicorn",
|
|
28
|
+
"z3",
|
|
29
|
+
]
|
|
21
30
|
native_modules = {
|
|
22
31
|
"angr": lambda: angr.state_plugins.unicorn_engine._UC_NATIVE, # pylint: disable=undefined-variable
|
|
23
|
-
"unicorn": lambda: unicorn.unicorn._uc, # pylint: disable=undefined-variable
|
|
24
32
|
"pyvex": lambda: pyvex.pvc, # pylint: disable=undefined-variable
|
|
33
|
+
"unicorn": lambda: unicorn.unicorn._uc, # pylint: disable=undefined-variable
|
|
25
34
|
"z3": lambda: next(x for x in gc.get_objects() if type(x) is ctypes.CDLL and "z3" in str(x)), # YIKES FOREVER
|
|
26
35
|
}
|
|
27
36
|
python_packages = {"z3": "z3-solver"}
|
|
@@ -161,13 +161,12 @@ class SimLibrary:
|
|
|
161
161
|
for arch_name, cc_name in d["default_cc"].items():
|
|
162
162
|
cc = CC_NAMES[cc_name]
|
|
163
163
|
lib.set_default_cc(arch_name, cc)
|
|
164
|
-
if "aliases" in d:
|
|
165
|
-
for name, alt_names in d["aliases"].items():
|
|
166
|
-
lib.add_alias(name, *alt_names)
|
|
167
164
|
if "library_names" in d:
|
|
168
165
|
lib.set_library_names(*d["library_names"])
|
|
169
166
|
else:
|
|
170
167
|
raise KeyError("library_names is required")
|
|
168
|
+
if "non_returning" in d:
|
|
169
|
+
lib.set_non_returning(*d["non_returning"])
|
|
171
170
|
if "functions" in d:
|
|
172
171
|
lib.prototypes_json = {k: v["proto"] for k, v in d["functions"].items() if "proto" in v}
|
|
173
172
|
return lib
|
|
@@ -307,8 +306,8 @@ class SimLibrary:
|
|
|
307
306
|
new_procedure = copy.deepcopy(old_procedure)
|
|
308
307
|
new_procedure.display_name = alt
|
|
309
308
|
self.procedures[alt] = new_procedure
|
|
310
|
-
if
|
|
311
|
-
self.prototypes[alt] = self.
|
|
309
|
+
if self.has_prototype(name):
|
|
310
|
+
self.prototypes[alt] = self.get_prototype(name) # type:ignore
|
|
312
311
|
if name in self.non_returning:
|
|
313
312
|
self.non_returning.add(alt)
|
|
314
313
|
|
|
@@ -317,8 +316,8 @@ class SimLibrary:
|
|
|
317
316
|
proc.cc = self.default_ccs[arch.name](arch)
|
|
318
317
|
if proc.cc is None and arch.name in self.fallback_cc:
|
|
319
318
|
proc.cc = self.fallback_cc[arch.name]["Linux"](arch)
|
|
320
|
-
if proc.display_name
|
|
321
|
-
proc.prototype = self.
|
|
319
|
+
if self.has_prototype(proc.display_name):
|
|
320
|
+
proc.prototype = self.get_prototype(proc.display_name, deref=True).with_arch(arch) # type:ignore
|
|
322
321
|
proc.guessed_prototype = False
|
|
323
322
|
if proc.prototype.arg_names is None:
|
|
324
323
|
# Use inspect to extract the parameters from the run python function
|
|
@@ -361,12 +360,13 @@ class SimLibrary:
|
|
|
361
360
|
self._apply_metadata(proc, arch)
|
|
362
361
|
return proc
|
|
363
362
|
|
|
364
|
-
def get_prototype(self, name: str, arch=None) -> SimTypeFunction | None:
|
|
363
|
+
def get_prototype(self, name: str, arch=None, deref: bool = False) -> SimTypeFunction | None:
|
|
365
364
|
"""
|
|
366
365
|
Get a prototype of the given function name, optionally specialize the prototype to a given architecture.
|
|
367
366
|
|
|
368
367
|
:param name: Name of the function.
|
|
369
368
|
:param arch: The architecture to specialize to.
|
|
369
|
+
:param deref: True if any SimTypeRefs in the prototype should be dereferenced using library information.
|
|
370
370
|
:return: Prototype of the function, or None if the prototype does not exist.
|
|
371
371
|
"""
|
|
372
372
|
if name not in self.prototypes and name in self.prototypes_json:
|
|
@@ -389,6 +389,11 @@ class SimLibrary:
|
|
|
389
389
|
proto = self.prototypes.get(name, None)
|
|
390
390
|
if proto is None:
|
|
391
391
|
return None
|
|
392
|
+
if deref:
|
|
393
|
+
from angr.utils.types import dereference_simtype_by_lib # pylint:disable=import-outside-toplevel
|
|
394
|
+
|
|
395
|
+
proto = dereference_simtype_by_lib(proto, self.name)
|
|
396
|
+
assert isinstance(proto, SimTypeFunction)
|
|
392
397
|
if arch is not None:
|
|
393
398
|
return proto.with_arch(arch)
|
|
394
399
|
return proto
|
|
@@ -400,7 +405,7 @@ class SimLibrary:
|
|
|
400
405
|
:param name: The name of the function as a string
|
|
401
406
|
:return: A bool indicating if anything is known about the function
|
|
402
407
|
"""
|
|
403
|
-
return self.has_implementation(name) or name in self.non_returning or
|
|
408
|
+
return self.has_implementation(name) or name in self.non_returning or self.has_prototype(name)
|
|
404
409
|
|
|
405
410
|
def has_implementation(self, name):
|
|
406
411
|
"""
|
|
@@ -490,17 +495,18 @@ class SimCppLibrary(SimLibrary):
|
|
|
490
495
|
stub.num_args = len(stub.prototype.args)
|
|
491
496
|
return stub
|
|
492
497
|
|
|
493
|
-
def get_prototype(self, name: str, arch=None) -> SimTypeFunction | None:
|
|
498
|
+
def get_prototype(self, name: str, arch=None, deref: bool = False) -> SimTypeFunction | None:
|
|
494
499
|
"""
|
|
495
500
|
Get a prototype of the given function name, optionally specialize the prototype to a given architecture. The
|
|
496
501
|
function name will be demangled first.
|
|
497
502
|
|
|
498
503
|
:param name: Name of the function.
|
|
499
504
|
:param arch: The architecture to specialize to.
|
|
505
|
+
:param deref: True if any SimTypeRefs in the prototype should be dereferenced using library information.
|
|
500
506
|
:return: Prototype of the function, or None if the prototype does not exist.
|
|
501
507
|
"""
|
|
502
508
|
demangled_name = self._try_demangle(name)
|
|
503
|
-
return super().get_prototype(demangled_name, arch=arch)
|
|
509
|
+
return super().get_prototype(demangled_name, arch=arch, deref=deref)
|
|
504
510
|
|
|
505
511
|
def has_metadata(self, name):
|
|
506
512
|
"""
|
|
@@ -659,11 +665,39 @@ class SimSyscallLibrary(SimLibrary):
|
|
|
659
665
|
if abi in self.default_cc_mapping:
|
|
660
666
|
cc = self.default_cc_mapping[abi](arch)
|
|
661
667
|
proc.cc = cc
|
|
668
|
+
elif arch.name in self.default_ccs:
|
|
669
|
+
proc.cc = self.default_ccs[arch.name](arch)
|
|
662
670
|
# a bit of a hack.
|
|
663
671
|
name = proc.display_name
|
|
664
|
-
if self.
|
|
672
|
+
if self.has_prototype(abi, name):
|
|
665
673
|
proc.guessed_prototype = False
|
|
666
|
-
|
|
674
|
+
proto = self.get_prototype(abi, name, deref=True)
|
|
675
|
+
assert proto is not None
|
|
676
|
+
proc.prototype = proto.with_arch(arch)
|
|
677
|
+
|
|
678
|
+
def add_alias(self, name, *alt_names):
|
|
679
|
+
"""
|
|
680
|
+
Add some duplicate names for a given function. The original function's implementation must already be
|
|
681
|
+
registered.
|
|
682
|
+
|
|
683
|
+
:param name: The name of the function for which an implementation is already present
|
|
684
|
+
:param alt_names: Any number of alternate names may be passed as varargs
|
|
685
|
+
"""
|
|
686
|
+
old_procedure = self.procedures[name]
|
|
687
|
+
for alt in alt_names:
|
|
688
|
+
new_procedure = copy.deepcopy(old_procedure)
|
|
689
|
+
new_procedure.display_name = alt
|
|
690
|
+
self.procedures[alt] = new_procedure
|
|
691
|
+
for abi in self.syscall_prototypes:
|
|
692
|
+
if self.has_prototype(abi, name):
|
|
693
|
+
self.syscall_prototypes[abi][alt] = self.get_prototype(abi, name) # type:ignore
|
|
694
|
+
if name in self.non_returning:
|
|
695
|
+
self.non_returning.add(alt)
|
|
696
|
+
|
|
697
|
+
def _apply_metadata(self, proc, arch):
|
|
698
|
+
# this function is a no-op in SimSyscallLibrary; users are supposed to explicitly call
|
|
699
|
+
# _apply_numerical_metadata instead.
|
|
700
|
+
pass
|
|
667
701
|
|
|
668
702
|
# pylint: disable=arguments-differ
|
|
669
703
|
def get(self, number, arch, abi_list=()): # type:ignore
|
|
@@ -703,7 +737,9 @@ class SimSyscallLibrary(SimLibrary):
|
|
|
703
737
|
l.debug("unsupported syscall: %s", number)
|
|
704
738
|
return proc
|
|
705
739
|
|
|
706
|
-
def get_prototype(
|
|
740
|
+
def get_prototype( # type:ignore
|
|
741
|
+
self, abi: str, name: str, arch=None, deref: bool = False
|
|
742
|
+
) -> SimTypeFunction | None:
|
|
707
743
|
"""
|
|
708
744
|
Get a prototype of the given syscall name and its ABI, optionally specialize the prototype to a given
|
|
709
745
|
architecture.
|
|
@@ -711,6 +747,7 @@ class SimSyscallLibrary(SimLibrary):
|
|
|
711
747
|
:param abi: ABI of the prototype to get.
|
|
712
748
|
:param name: Name of the syscall.
|
|
713
749
|
:param arch: The architecture to specialize to.
|
|
750
|
+
:param deref: True if any SimTypeRefs in the prototype should be dereferenced using library information.
|
|
714
751
|
:return: Prototype of the syscall, or None if the prototype does not exist.
|
|
715
752
|
"""
|
|
716
753
|
if abi not in self.syscall_prototypes:
|
|
@@ -718,6 +755,11 @@ class SimSyscallLibrary(SimLibrary):
|
|
|
718
755
|
proto = self.syscall_prototypes[abi].get(name, None)
|
|
719
756
|
if proto is None:
|
|
720
757
|
return None
|
|
758
|
+
if deref:
|
|
759
|
+
from angr.utils.types import dereference_simtype_by_lib # pylint:disable=import-outside-toplevel
|
|
760
|
+
|
|
761
|
+
proto = dereference_simtype_by_lib(proto, self.name)
|
|
762
|
+
assert isinstance(proto, SimTypeFunction)
|
|
721
763
|
return proto.with_arch(arch=arch)
|
|
722
764
|
|
|
723
765
|
def has_metadata(self, number, arch, abi_list=()): # type:ignore
|
|
@@ -729,8 +771,10 @@ class SimSyscallLibrary(SimLibrary):
|
|
|
729
771
|
:param abi_list: A list of ABI names that could be used
|
|
730
772
|
:return: A bool of whether or not any implementation or metadata is known about the given syscall
|
|
731
773
|
"""
|
|
732
|
-
name, _,
|
|
733
|
-
return
|
|
774
|
+
name, _, abi = self._canonicalize(number, arch, abi_list)
|
|
775
|
+
return (
|
|
776
|
+
name in self.procedures or name in self.non_returning or (abi is not None and self.has_prototype(abi, name))
|
|
777
|
+
)
|
|
734
778
|
|
|
735
779
|
def has_implementation(self, number, arch, abi_list=()): # type:ignore
|
|
736
780
|
"""
|
|
@@ -879,7 +923,7 @@ def load_external_definitions():
|
|
|
879
923
|
|
|
880
924
|
|
|
881
925
|
def _update_libkernel32(lib: SimLibrary):
|
|
882
|
-
from angr import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
|
|
926
|
+
from angr.procedures.procedure_dict import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
|
|
883
927
|
|
|
884
928
|
lib.add_all_from_dict(P["win32"])
|
|
885
929
|
lib.add_alias("EncodePointer", "DecodePointer")
|
|
@@ -895,7 +939,7 @@ def _update_libkernel32(lib: SimLibrary):
|
|
|
895
939
|
|
|
896
940
|
|
|
897
941
|
def _update_libntdll(lib: SimLibrary):
|
|
898
|
-
from angr import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
|
|
942
|
+
from angr.procedures.procedure_dict import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
|
|
899
943
|
|
|
900
944
|
lib.add("RtlEncodePointer", P["win32"]["EncodePointer"])
|
|
901
945
|
lib.add("RtlDecodePointer", P["win32"]["EncodePointer"])
|
|
@@ -903,7 +947,7 @@ def _update_libntdll(lib: SimLibrary):
|
|
|
903
947
|
|
|
904
948
|
|
|
905
949
|
def _update_libuser32(lib: SimLibrary):
|
|
906
|
-
from angr import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
|
|
950
|
+
from angr.procedures.procedure_dict import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
|
|
907
951
|
from angr.calling_conventions import SimCCCdecl # pylint:disable=import-outside-toplevel
|
|
908
952
|
|
|
909
953
|
lib.add_all_from_dict(P["win_user32"])
|
|
@@ -911,11 +955,33 @@ def _update_libuser32(lib: SimLibrary):
|
|
|
911
955
|
|
|
912
956
|
|
|
913
957
|
def _update_libntoskrnl(lib: SimLibrary):
|
|
914
|
-
from angr import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
|
|
958
|
+
from angr.procedures.procedure_dict import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
|
|
915
959
|
|
|
916
960
|
lib.add_all_from_dict(P["win32_kernel"])
|
|
917
961
|
|
|
918
962
|
|
|
963
|
+
def _update_glibc(libc: SimLibrary):
|
|
964
|
+
from angr.procedures.procedure_dict import SIM_PROCEDURES as P # pylint:disable=import-outside-toplevel
|
|
965
|
+
|
|
966
|
+
libc.add_all_from_dict(P["libc"])
|
|
967
|
+
libc.add_all_from_dict(P["posix"])
|
|
968
|
+
libc.add_all_from_dict(P["glibc"])
|
|
969
|
+
# gotta do this since there's no distinguishing different libcs without analysis. there should be no naming
|
|
970
|
+
# conflicts in the functions.
|
|
971
|
+
libc.add_all_from_dict(P["uclibc"])
|
|
972
|
+
|
|
973
|
+
# aliases for SimProcedures
|
|
974
|
+
libc.add_alias("abort", "__assert_fail", "__stack_chk_fail")
|
|
975
|
+
libc.add_alias("memcpy", "memmove", "bcopy")
|
|
976
|
+
libc.add_alias("getc", "_IO_getc")
|
|
977
|
+
libc.add_alias("putc", "_IO_putc")
|
|
978
|
+
libc.add_alias("gets", "_IO_gets")
|
|
979
|
+
libc.add_alias("puts", "_IO_puts")
|
|
980
|
+
libc.add_alias("exit", "_exit", "_Exit")
|
|
981
|
+
libc.add_alias("sprintf", "siprintf")
|
|
982
|
+
libc.add_alias("snprintf", "sniprintf")
|
|
983
|
+
|
|
984
|
+
|
|
919
985
|
def load_win32api_definitions():
|
|
920
986
|
load_win32_type_collections()
|
|
921
987
|
if once("load_win32api_definitions"):
|
|
@@ -961,4 +1027,6 @@ load_type_collections(skip={"win32"})
|
|
|
961
1027
|
|
|
962
1028
|
|
|
963
1029
|
# Load common definitions
|
|
1030
|
+
_load_definitions(os.path.join(_DEFINITIONS_BASEDIR, "common"), only=COMMON_LIBRARIES)
|
|
964
1031
|
_load_definitions(_DEFINITIONS_BASEDIR, only=COMMON_LIBRARIES)
|
|
1032
|
+
_update_glibc(SIM_LIBRARIES["libc.so"][0])
|