angr 9.2.147__py3-none-win_amd64.whl → 9.2.149__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/analysis.py +3 -11
- angr/analyses/calling_convention/calling_convention.py +42 -2
- angr/analyses/calling_convention/fact_collector.py +5 -4
- angr/analyses/calling_convention/utils.py +1 -0
- angr/analyses/cfg/cfg_base.py +3 -59
- angr/analyses/cfg/cfg_emulated.py +17 -14
- angr/analyses/cfg/cfg_fast.py +68 -63
- angr/analyses/cfg/cfg_fast_soot.py +3 -3
- angr/analyses/decompiler/ail_simplifier.py +65 -32
- angr/analyses/decompiler/block_simplifier.py +20 -6
- angr/analyses/decompiler/callsite_maker.py +28 -18
- angr/analyses/decompiler/clinic.py +84 -17
- angr/analyses/decompiler/condition_processor.py +0 -21
- angr/analyses/decompiler/counters/call_counter.py +3 -0
- angr/analyses/decompiler/dephication/rewriting_engine.py +24 -2
- angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
- angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +15 -13
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +1 -1
- angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
- angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +165 -0
- angr/analyses/decompiler/optimization_passes/engine_base.py +11 -2
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +17 -2
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +10 -6
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +99 -30
- angr/analyses/decompiler/peephole_optimizations/__init__.py +6 -0
- angr/analyses/decompiler/peephole_optimizations/base.py +43 -3
- angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +3 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +4 -1
- angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +69 -2
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +14 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
- angr/analyses/decompiler/presets/fast.py +2 -0
- angr/analyses/decompiler/presets/full.py +2 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +51 -4
- angr/analyses/decompiler/ssailification/ssailification.py +23 -3
- angr/analyses/decompiler/ssailification/traversal_engine.py +15 -1
- angr/analyses/decompiler/structured_codegen/c.py +146 -15
- angr/analyses/decompiler/structuring/phoenix.py +11 -3
- angr/analyses/decompiler/utils.py +6 -1
- angr/analyses/deobfuscator/api_obf_finder.py +5 -1
- angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
- angr/analyses/forward_analysis/visitors/graph.py +0 -8
- angr/analyses/identifier/runner.py +1 -1
- angr/analyses/reaching_definitions/function_handler.py +4 -4
- angr/analyses/reassembler.py +1 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +1 -0
- angr/analyses/stack_pointer_tracker.py +1 -1
- angr/analyses/static_hooker.py +11 -9
- angr/analyses/typehoon/lifter.py +20 -0
- angr/analyses/typehoon/simple_solver.py +42 -9
- angr/analyses/typehoon/translator.py +4 -1
- angr/analyses/typehoon/typeconsts.py +17 -6
- angr/analyses/typehoon/typehoon.py +21 -5
- angr/analyses/variable_recovery/engine_ail.py +52 -13
- angr/analyses/variable_recovery/engine_base.py +37 -12
- angr/analyses/variable_recovery/variable_recovery_fast.py +33 -2
- angr/calling_conventions.py +96 -27
- angr/engines/light/engine.py +7 -0
- angr/exploration_techniques/director.py +1 -1
- angr/knowledge_plugins/functions/function.py +109 -38
- angr/knowledge_plugins/functions/function_manager.py +9 -0
- angr/knowledge_plugins/functions/function_parser.py +9 -1
- angr/knowledge_plugins/functions/soot_function.py +1 -1
- angr/knowledge_plugins/key_definitions/key_definition_manager.py +1 -1
- angr/knowledge_plugins/propagations/states.py +5 -2
- angr/knowledge_plugins/variables/variable_manager.py +3 -3
- angr/lib/angr_native.dll +0 -0
- angr/procedures/definitions/__init__.py +15 -12
- angr/procedures/definitions/types_stl.py +22 -0
- angr/procedures/stubs/format_parser.py +1 -1
- angr/project.py +23 -29
- angr/protos/cfg_pb2.py +14 -25
- angr/protos/function_pb2.py +11 -22
- angr/protos/primitives_pb2.py +36 -47
- angr/protos/variables_pb2.py +28 -39
- angr/protos/xrefs_pb2.py +8 -19
- angr/sim_type.py +251 -146
- angr/simos/cgc.py +1 -1
- angr/simos/linux.py +5 -5
- angr/simos/windows.py +5 -5
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -1
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/METADATA +9 -8
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/RECORD +91 -85
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/WHEEL +1 -1
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info/licenses}/LICENSE +3 -0
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/entry_points.txt +0 -0
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/top_level.txt +0 -0
|
@@ -70,9 +70,12 @@ class SimEngineVRBase(
|
|
|
70
70
|
and storing data.
|
|
71
71
|
"""
|
|
72
72
|
|
|
73
|
-
def __init__(self, project, kb):
|
|
73
|
+
def __init__(self, project, kb, vvar_type_hints: dict[int, typeconsts.TypeConstant] | None = None):
|
|
74
74
|
super().__init__(project)
|
|
75
75
|
|
|
76
|
+
self.vvar_type_hints: dict[int, typeconsts.TypeConstant] = (
|
|
77
|
+
vvar_type_hints if vvar_type_hints is not None else {}
|
|
78
|
+
)
|
|
76
79
|
self.kb = kb
|
|
77
80
|
self.vvar_region: dict[int, Any] = {}
|
|
78
81
|
|
|
@@ -417,6 +420,7 @@ class SimEngineVRBase(
|
|
|
417
420
|
vvar.size,
|
|
418
421
|
ident=self.state.variable_manager[self.func_addr].next_variable_ident("stack"),
|
|
419
422
|
region=self.func_addr,
|
|
423
|
+
base="bp",
|
|
420
424
|
)
|
|
421
425
|
self.state.variable_manager[self.func_addr].add_variable("stack", vvar.stack_offset, variable)
|
|
422
426
|
elif vvar.was_parameter:
|
|
@@ -452,13 +456,19 @@ class SimEngineVRBase(
|
|
|
452
456
|
# assign a new type variable to it
|
|
453
457
|
typevar = typevars.TypeVariable()
|
|
454
458
|
self.state.typevars.add_type_variable(variable, typevar)
|
|
455
|
-
# create constraints
|
|
456
459
|
else:
|
|
457
460
|
typevar = self.state.typevars.get_type_variable(variable)
|
|
461
|
+
|
|
462
|
+
# create constraints accordingly
|
|
463
|
+
|
|
458
464
|
self.state.add_type_constraint(typevars.Subtype(richr.typevar, typevar))
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
465
|
+
if vvar.varid in self.vvar_type_hints:
|
|
466
|
+
# handle type hints
|
|
467
|
+
self.state.add_type_constraint(typevars.Subtype(typevar, self.vvar_type_hints[vvar.varid]))
|
|
468
|
+
else:
|
|
469
|
+
# the constraint below is a default constraint that may conflict with more specific ones with different
|
|
470
|
+
# sizes; we post-process at the very end of VRA to remove conflicting default constraints.
|
|
471
|
+
self.state.add_type_constraint(typevars.Subtype(typevar, typeconsts.int_type(variable.size * 8)))
|
|
462
472
|
|
|
463
473
|
return variable
|
|
464
474
|
|
|
@@ -977,14 +987,22 @@ class SimEngineVRBase(
|
|
|
977
987
|
value = self.state.top(size * self.project.arch.byte_width)
|
|
978
988
|
if create_variable:
|
|
979
989
|
# create a new variable if necessary
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
990
|
+
|
|
991
|
+
# check if there is an existing variable for the atom at this location already
|
|
992
|
+
existing_vars: set[tuple[SimVariable, int]] = self.state.variable_manager[
|
|
993
|
+
self.func_addr
|
|
994
|
+
].find_variables_by_atom(self.block.addr, self.stmt_idx, expr)
|
|
995
|
+
if not existing_vars:
|
|
996
|
+
variable = SimRegisterVariable(
|
|
997
|
+
offset,
|
|
998
|
+
size if force_variable_size is None else force_variable_size,
|
|
999
|
+
ident=self.state.variable_manager[self.func_addr].next_variable_ident("register"),
|
|
1000
|
+
region=self.func_addr,
|
|
1001
|
+
)
|
|
1002
|
+
self.state.variable_manager[self.func_addr].add_variable("register", offset, variable)
|
|
1003
|
+
else:
|
|
1004
|
+
variable = next(iter(existing_vars))[0]
|
|
986
1005
|
value = self.state.annotate_with_variables(value, [(0, variable)])
|
|
987
|
-
self.state.variable_manager[self.func_addr].add_variable("register", offset, variable)
|
|
988
1006
|
self.state.register_region.store(offset, value)
|
|
989
1007
|
value_list = [{value}]
|
|
990
1008
|
else:
|
|
@@ -1079,6 +1097,7 @@ class SimEngineVRBase(
|
|
|
1079
1097
|
vvar.size,
|
|
1080
1098
|
ident=self.state.variable_manager[self.func_addr].next_variable_ident("stack"),
|
|
1081
1099
|
region=self.func_addr,
|
|
1100
|
+
base="bp",
|
|
1082
1101
|
)
|
|
1083
1102
|
value = self.state.annotate_with_variables(value, [(0, variable)])
|
|
1084
1103
|
self.state.variable_manager[self.func_addr].add_variable("stack", vvar.stack_offset, variable)
|
|
@@ -1129,6 +1148,12 @@ class SimEngineVRBase(
|
|
|
1129
1148
|
if var is not None and var.size != vvar.size:
|
|
1130
1149
|
# ignore the variable and the associated type if we are only reading part of the variable
|
|
1131
1150
|
return RichR(value, variable=var)
|
|
1151
|
+
|
|
1152
|
+
# handle type hints
|
|
1153
|
+
if vvar.varid in self.vvar_type_hints:
|
|
1154
|
+
assert isinstance(typevar, typevars.TypeVariable)
|
|
1155
|
+
self.state.add_type_constraint(typevars.Subtype(typevar, self.vvar_type_hints[vvar.varid]))
|
|
1156
|
+
|
|
1132
1157
|
return RichR(value, variable=var, typevar=typevar)
|
|
1133
1158
|
|
|
1134
1159
|
def _create_access_typevar(
|
|
@@ -12,21 +12,25 @@ import ailment
|
|
|
12
12
|
from ailment.expression import VirtualVariable
|
|
13
13
|
|
|
14
14
|
import angr.errors
|
|
15
|
+
from angr import SIM_TYPE_COLLECTIONS
|
|
15
16
|
from angr.analyses import AnalysesHub
|
|
16
17
|
from angr.storage.memory_mixins.paged_memory.pages.multi_values import MultiValues
|
|
17
18
|
from angr.block import Block
|
|
18
19
|
from angr.errors import AngrVariableRecoveryError, SimEngineError
|
|
19
20
|
from angr.knowledge_plugins import Function
|
|
21
|
+
from angr.knowledge_plugins.key_definitions import atoms
|
|
20
22
|
from angr.sim_variable import SimStackVariable, SimRegisterVariable, SimVariable, SimMemoryVariable
|
|
21
23
|
from angr.engines.vex.claripy.irop import vexop_to_simop
|
|
22
24
|
from angr.analyses import ForwardAnalysis, visitors
|
|
23
25
|
from angr.analyses.typehoon.typevars import Equivalence, TypeVariable, TypeVariables, Subtype, DerivedTypeVariable
|
|
24
|
-
from angr.analyses.typehoon.typeconsts import Int
|
|
26
|
+
from angr.analyses.typehoon.typeconsts import Int, TypeConstant, BottomType, TopType
|
|
27
|
+
from angr.analyses.typehoon.lifter import TypeLifter
|
|
25
28
|
from .variable_recovery_base import VariableRecoveryBase, VariableRecoveryStateBase
|
|
26
29
|
from .engine_vex import SimEngineVRVEX
|
|
27
30
|
from .engine_ail import SimEngineVRAIL
|
|
28
31
|
import contextlib
|
|
29
32
|
|
|
33
|
+
|
|
30
34
|
if TYPE_CHECKING:
|
|
31
35
|
from angr.analyses.typehoon.typevars import TypeConstraint
|
|
32
36
|
|
|
@@ -241,6 +245,7 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
241
245
|
unify_variables=True,
|
|
242
246
|
func_arg_vvars: dict[int, tuple[VirtualVariable, SimVariable]] | None = None,
|
|
243
247
|
vvar_to_vvar: dict[int, int] | None = None,
|
|
248
|
+
type_hints: list[tuple[atoms.VirtualVariable | atoms.MemoryLocation, str]] | None = None,
|
|
244
249
|
):
|
|
245
250
|
if not isinstance(func, Function):
|
|
246
251
|
func = self.kb.functions[func]
|
|
@@ -269,8 +274,17 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
269
274
|
self._func_arg_vvars = func_arg_vvars
|
|
270
275
|
self._unify_variables = unify_variables
|
|
271
276
|
|
|
277
|
+
# handle type hints
|
|
278
|
+
self.vvar_type_hints = {}
|
|
279
|
+
if type_hints:
|
|
280
|
+
self._parse_type_hints(type_hints)
|
|
281
|
+
|
|
272
282
|
self._ail_engine: SimEngineVRAIL = SimEngineVRAIL(
|
|
273
|
-
self.project,
|
|
283
|
+
self.project,
|
|
284
|
+
self.kb,
|
|
285
|
+
call_info=call_info,
|
|
286
|
+
vvar_to_vvar=self.vvar_to_vvar,
|
|
287
|
+
vvar_type_hints=self.vvar_type_hints,
|
|
274
288
|
)
|
|
275
289
|
self._vex_engine: SimEngineVRVEX = SimEngineVRVEX(self.project, self.kb, call_info=call_info)
|
|
276
290
|
|
|
@@ -617,5 +631,22 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
617
631
|
if adjusted:
|
|
618
632
|
state.register_region.store(self.project.arch.sp_offset, sp_v)
|
|
619
633
|
|
|
634
|
+
def _parse_type_hints(self, type_hints: list[tuple[atoms.VirtualVariable | atoms.MemoryLocation, str]]) -> None:
|
|
635
|
+
self.vvar_type_hints = {}
|
|
636
|
+
for loc, type_hint_str in type_hints:
|
|
637
|
+
if isinstance(loc, atoms.VirtualVariable):
|
|
638
|
+
type_hint = self._parse_type_hint(type_hint_str)
|
|
639
|
+
if type_hint is not None:
|
|
640
|
+
self.vvar_type_hints[loc.varid] = type_hint
|
|
641
|
+
# TODO: Handle other types of locations
|
|
642
|
+
|
|
643
|
+
def _parse_type_hint(self, type_hint_str: str) -> TypeConstant | None:
|
|
644
|
+
ty = SIM_TYPE_COLLECTIONS["cpp::std"].get(type_hint_str)
|
|
645
|
+
if ty is None:
|
|
646
|
+
return None
|
|
647
|
+
ty = ty.with_arch(self.project.arch)
|
|
648
|
+
lifted = TypeLifter(self.project.arch.bits).lift(ty)
|
|
649
|
+
return None if isinstance(lifted, (BottomType, TopType)) else lifted
|
|
650
|
+
|
|
620
651
|
|
|
621
652
|
AnalysesHub.register_default("VariableRecoveryFast", VariableRecoveryFast)
|
angr/calling_conventions.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# pylint:disable=line-too-long,missing-class-docstring,no-self-use
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
import logging
|
|
4
|
-
from typing import cast
|
|
4
|
+
from typing import Generic, cast, TypeVar
|
|
5
5
|
|
|
6
|
-
from collections.abc import Iterable
|
|
6
|
+
from collections.abc import Iterable
|
|
7
7
|
from collections import defaultdict
|
|
8
8
|
import contextlib
|
|
9
9
|
|
|
@@ -39,6 +39,8 @@ from .state_plugins.sim_action_object import SimActionObject
|
|
|
39
39
|
l = logging.getLogger(name=__name__)
|
|
40
40
|
l.addFilter(UniqueLogFilter())
|
|
41
41
|
|
|
42
|
+
T = TypeVar("T", bound="SimFunctionArgument")
|
|
43
|
+
|
|
42
44
|
|
|
43
45
|
class PointerWrapper:
|
|
44
46
|
def __init__(self, value, buffer=False):
|
|
@@ -386,12 +388,12 @@ class SimStackArg(SimFunctionArgument):
|
|
|
386
388
|
return SimStackArg(self.stack_offset + offset, size, is_fp)
|
|
387
389
|
|
|
388
390
|
|
|
389
|
-
class SimComboArg(SimFunctionArgument):
|
|
391
|
+
class SimComboArg(SimFunctionArgument, Generic[T]):
|
|
390
392
|
"""
|
|
391
393
|
An argument which spans multiple storage locations. Locations should be given least-significant first.
|
|
392
394
|
"""
|
|
393
395
|
|
|
394
|
-
def __init__(self, locations, is_fp=False):
|
|
396
|
+
def __init__(self, locations: list[T], is_fp=False):
|
|
395
397
|
super().__init__(sum(x.size for x in locations), is_fp=is_fp)
|
|
396
398
|
self.locations = locations
|
|
397
399
|
|
|
@@ -449,6 +451,45 @@ class SimStructArg(SimFunctionArgument):
|
|
|
449
451
|
|
|
450
452
|
return others
|
|
451
453
|
|
|
454
|
+
def get_single_footprint(self) -> SimStackArg | SimRegArg | SimComboArg:
|
|
455
|
+
if self.struct._arch is None:
|
|
456
|
+
raise TypeError("Can't tell the size of a struct without an arch")
|
|
457
|
+
stack_min = None
|
|
458
|
+
stack_max = None
|
|
459
|
+
regs = []
|
|
460
|
+
for field in self.struct.fields:
|
|
461
|
+
loc = self.locs[field]
|
|
462
|
+
if isinstance(loc, SimStackArg):
|
|
463
|
+
if stack_min is None or stack_max is None:
|
|
464
|
+
stack_min = loc.stack_offset
|
|
465
|
+
stack_max = loc.stack_offset
|
|
466
|
+
else:
|
|
467
|
+
# sanity check that arguments are laid out in order...
|
|
468
|
+
assert loc.stack_offset >= stack_max
|
|
469
|
+
stack_max = loc.stack_offset + loc.size
|
|
470
|
+
elif isinstance(loc, SimRegArg):
|
|
471
|
+
regs.append(loc)
|
|
472
|
+
else:
|
|
473
|
+
assert False, "Why would a struct have layout elements other than stack and reg?"
|
|
474
|
+
|
|
475
|
+
# things to consider...
|
|
476
|
+
# what happens if we return the concat of two registers but there's slack space missing?
|
|
477
|
+
# an example of this would be big-endian struct { long a; int b; }
|
|
478
|
+
# do any CCs do this??
|
|
479
|
+
# for now assume no
|
|
480
|
+
|
|
481
|
+
if stack_min is not None:
|
|
482
|
+
if regs:
|
|
483
|
+
assert (
|
|
484
|
+
False
|
|
485
|
+
), "Unknown CC argument passing structure - why are we passing both regs and stack at the same time?"
|
|
486
|
+
return SimStackArg(stack_min, self.struct.size // self.struct._arch.byte_width)
|
|
487
|
+
if not regs:
|
|
488
|
+
assert False, "huh??????"
|
|
489
|
+
if len(regs) == 1:
|
|
490
|
+
return regs[0]
|
|
491
|
+
return SimComboArg(regs)
|
|
492
|
+
|
|
452
493
|
def get_value(self, state, **kwargs):
|
|
453
494
|
return SimStructValue(
|
|
454
495
|
self.struct, {field: getter.get_value(state, **kwargs) for field, getter in self.locs.items()}
|
|
@@ -486,7 +527,7 @@ class SimReferenceArgument(SimFunctionArgument):
|
|
|
486
527
|
zero on the stack. It will be passed ``stack_base=ptr_loc.get_value(state)``
|
|
487
528
|
"""
|
|
488
529
|
|
|
489
|
-
def __init__(self, ptr_loc, main_loc):
|
|
530
|
+
def __init__(self, ptr_loc: SimFunctionArgument, main_loc: SimFunctionArgument):
|
|
490
531
|
super().__init__(ptr_loc.size) # ???
|
|
491
532
|
self.ptr_loc = ptr_loc
|
|
492
533
|
self.main_loc = main_loc
|
|
@@ -700,6 +741,7 @@ class SimCC:
|
|
|
700
741
|
)
|
|
701
742
|
if self.return_in_implicit_outparam(ty):
|
|
702
743
|
if perspective_returned:
|
|
744
|
+
assert self.RETURN_VAL is not None
|
|
703
745
|
ptr_loc = self.RETURN_VAL
|
|
704
746
|
else:
|
|
705
747
|
ptr_loc = self.next_arg(self.ArgSession(self), SimTypePointer(SimTypeBottom()))
|
|
@@ -713,6 +755,7 @@ class SimCC:
|
|
|
713
755
|
if self.RETURN_VAL is None or isinstance(ty, SimTypeBottom):
|
|
714
756
|
return None
|
|
715
757
|
if ty.size > self.RETURN_VAL.size * self.arch.byte_width:
|
|
758
|
+
assert self.OVERFLOW_RETURN_VAL is not None
|
|
716
759
|
return SimComboArg([self.RETURN_VAL, self.OVERFLOW_RETURN_VAL])
|
|
717
760
|
return self.RETURN_VAL.refine(size=ty.size // self.arch.byte_width, arch=self.arch, is_fp=False)
|
|
718
761
|
|
|
@@ -991,7 +1034,8 @@ class SimCC:
|
|
|
991
1034
|
else:
|
|
992
1035
|
raise TypeError("PointerWrapper(buffer=True) can only be used with a bitvector or a bytestring")
|
|
993
1036
|
else:
|
|
994
|
-
|
|
1037
|
+
sub = ty.pts_to if isinstance(ty, SimTypePointer) else ty.refs
|
|
1038
|
+
child_type = SimTypeArray(sub) if isinstance(arg.value, (str, bytes, list)) else sub
|
|
995
1039
|
try:
|
|
996
1040
|
real_value = SimCC._standardize_value(arg.value, child_type, state, alloc)
|
|
997
1041
|
except TypeError as e: # this is a dangerous catch...
|
|
@@ -1003,32 +1047,34 @@ class SimCC:
|
|
|
1003
1047
|
|
|
1004
1048
|
if isinstance(arg, (str, bytes)):
|
|
1005
1049
|
# sanitize the argument and request standardization again with SimTypeArray
|
|
1006
|
-
if
|
|
1050
|
+
if isinstance(arg, str):
|
|
1007
1051
|
arg = arg.encode()
|
|
1008
1052
|
arg += b"\0"
|
|
1009
1053
|
if isinstance(ty, SimTypePointer) and isinstance(ty.pts_to, SimTypeChar):
|
|
1010
1054
|
pass
|
|
1011
|
-
elif isinstance(ty, SimTypeFixedSizeArray) and isinstance(ty.elem_type, SimTypeChar)
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
arg = arg.ljust(ty.length, b"\0")
|
|
1015
|
-
elif isinstance(ty, SimTypeArray) and isinstance(ty.elem_type, SimTypeChar):
|
|
1055
|
+
elif (isinstance(ty, SimTypeFixedSizeArray) and isinstance(ty.elem_type, SimTypeChar)) or (
|
|
1056
|
+
isinstance(ty, SimTypeArray) and isinstance(ty.elem_type, SimTypeChar)
|
|
1057
|
+
):
|
|
1016
1058
|
if ty.length is not None:
|
|
1017
1059
|
if len(arg) > ty.length:
|
|
1018
1060
|
raise TypeError(f"String {arg!r} is too long for {ty}")
|
|
1019
1061
|
arg = arg.ljust(ty.length, b"\0")
|
|
1020
1062
|
elif isinstance(ty, SimTypeString):
|
|
1021
|
-
if
|
|
1022
|
-
|
|
1023
|
-
|
|
1063
|
+
if ty.length is not None:
|
|
1064
|
+
if len(arg) > ty.length + 1:
|
|
1065
|
+
raise TypeError(f"String {arg!r} is too long for {ty}")
|
|
1066
|
+
arg = arg.ljust(ty.length + 1, b"\0")
|
|
1024
1067
|
else:
|
|
1025
1068
|
raise TypeError(f"Type mismatch: Expected {ty}, got char*")
|
|
1026
1069
|
return SimCC._standardize_value(list(arg), SimTypeArray(SimTypeChar(), len(arg)), state, alloc)
|
|
1027
1070
|
|
|
1028
1071
|
if isinstance(arg, list):
|
|
1029
|
-
if isinstance(ty,
|
|
1072
|
+
if isinstance(ty, SimTypePointer):
|
|
1030
1073
|
ref = True
|
|
1031
1074
|
subty = ty.pts_to
|
|
1075
|
+
elif isinstance(ty, SimTypeReference):
|
|
1076
|
+
ref = True
|
|
1077
|
+
subty = ty.refs
|
|
1032
1078
|
elif isinstance(ty, SimTypeArray):
|
|
1033
1079
|
ref = True
|
|
1034
1080
|
subty = ty.elem_type
|
|
@@ -1045,7 +1091,7 @@ class SimCC:
|
|
|
1045
1091
|
if isinstance(arg, (tuple, dict, SimStructValue)):
|
|
1046
1092
|
if not isinstance(ty, SimStruct):
|
|
1047
1093
|
raise TypeError(f"Type mismatch: Expected {ty}, got {type(arg)} (i.e. struct)")
|
|
1048
|
-
if
|
|
1094
|
+
if not isinstance(arg, SimStructValue):
|
|
1049
1095
|
if len(arg) != len(ty.fields):
|
|
1050
1096
|
raise TypeError(f"Wrong number of fields in struct, expected {len(ty.fields)} got {len(arg)}")
|
|
1051
1097
|
arg = SimStructValue(ty, arg)
|
|
@@ -1075,14 +1121,16 @@ class SimCC:
|
|
|
1075
1121
|
raise TypeError(f"Type mismatch: expected {ty}, got {arg.sort}")
|
|
1076
1122
|
return arg
|
|
1077
1123
|
if isinstance(ty, (SimTypeReg, SimTypeNum)):
|
|
1078
|
-
return arg.val_to_bv(ty.size, ty.signed)
|
|
1124
|
+
return arg.val_to_bv(ty.size, ty.signed if isinstance(ty, SimTypeNum) else False)
|
|
1079
1125
|
raise TypeError(f"Type mismatch: expected {ty}, got {arg.sort}")
|
|
1080
1126
|
|
|
1081
1127
|
if isinstance(arg, claripy.ast.BV):
|
|
1082
1128
|
if isinstance(ty, (SimTypeReg, SimTypeNum)):
|
|
1083
1129
|
if len(arg) != ty.size:
|
|
1084
1130
|
if arg.concrete:
|
|
1085
|
-
|
|
1131
|
+
size = ty.size
|
|
1132
|
+
assert size is not None
|
|
1133
|
+
return claripy.BVV(arg.concrete_value, size)
|
|
1086
1134
|
raise TypeError(f"Type mismatch of symbolic data: expected {ty}, got {len(arg)} bits")
|
|
1087
1135
|
return arg
|
|
1088
1136
|
if isinstance(ty, (SimTypeFloat)):
|
|
@@ -1101,7 +1149,7 @@ class SimCC:
|
|
|
1101
1149
|
return isinstance(other, self.__class__)
|
|
1102
1150
|
|
|
1103
1151
|
@classmethod
|
|
1104
|
-
def _match(cls, arch, args: list, sp_delta):
|
|
1152
|
+
def _match(cls, arch, args: list[SimRegArg | SimStackArg], sp_delta):
|
|
1105
1153
|
if (
|
|
1106
1154
|
cls.arches() is not None and ":" not in arch.name and not isinstance(arch, cls.arches())
|
|
1107
1155
|
): # pylint:disable=isinstance-second-argument-not-valid-type
|
|
@@ -1139,13 +1187,16 @@ class SimCC:
|
|
|
1139
1187
|
@classmethod
|
|
1140
1188
|
def _guess_arg_count(cls, args, limit: int = 64) -> int:
|
|
1141
1189
|
# pylint:disable=not-callable
|
|
1190
|
+
assert cls.ARCH is not None
|
|
1142
1191
|
stack_args = [a for a in args if isinstance(a, SimStackArg)]
|
|
1143
|
-
stack_arg_count = (
|
|
1192
|
+
stack_arg_count = (
|
|
1193
|
+
(max(a.stack_offset for a in stack_args) // cls.ARCH(archinfo.Endness.LE).bytes + 1) if stack_args else 0
|
|
1194
|
+
)
|
|
1144
1195
|
return min(limit, max(len(args), stack_arg_count))
|
|
1145
1196
|
|
|
1146
1197
|
@staticmethod
|
|
1147
1198
|
def find_cc(
|
|
1148
|
-
arch: archinfo.Arch, args:
|
|
1199
|
+
arch: archinfo.Arch, args: list[SimRegArg | SimStackArg], sp_delta: int, platform: str | None = "Linux"
|
|
1149
1200
|
) -> SimCC | None:
|
|
1150
1201
|
"""
|
|
1151
1202
|
Pinpoint the best-fit calling convention and return the corresponding SimCC instance, or None if no fit is
|
|
@@ -1229,7 +1280,7 @@ class SimCCUsercall(SimCC):
|
|
|
1229
1280
|
def next_arg(self, session, arg_type):
|
|
1230
1281
|
return next(session.real_args)
|
|
1231
1282
|
|
|
1232
|
-
def return_val(self, ty, **kwargs):
|
|
1283
|
+
def return_val(self, ty, **kwargs): # pylint: disable=unused-argument
|
|
1233
1284
|
return self.ret_loc
|
|
1234
1285
|
|
|
1235
1286
|
|
|
@@ -1284,6 +1335,21 @@ class SimCCMicrosoftCdecl(SimCCCdecl):
|
|
|
1284
1335
|
STRUCT_RETURN_THRESHOLD = 64
|
|
1285
1336
|
|
|
1286
1337
|
|
|
1338
|
+
class SimCCMicrosoftThiscall(SimCCCdecl):
|
|
1339
|
+
CALLEE_CLEANUP = True
|
|
1340
|
+
ARG_REGS = ["ecx"]
|
|
1341
|
+
CALLER_SAVED_REGS = ["eax", "ecx", "edx"]
|
|
1342
|
+
STRUCT_RETURN_THRESHOLD = 64
|
|
1343
|
+
|
|
1344
|
+
def arg_locs(self, prototype) -> list[SimFunctionArgument]:
|
|
1345
|
+
if prototype._arch is None:
|
|
1346
|
+
prototype = prototype.with_arch(self.arch)
|
|
1347
|
+
session = self.arg_session(prototype.returnty)
|
|
1348
|
+
if not prototype.args:
|
|
1349
|
+
return []
|
|
1350
|
+
return [SimRegArg("ecx", self.arch.bytes)] + [self.next_arg(session, arg_ty) for arg_ty in prototype.args[1:]]
|
|
1351
|
+
|
|
1352
|
+
|
|
1287
1353
|
class SimCCStdcall(SimCCMicrosoftCdecl):
|
|
1288
1354
|
CALLEE_CLEANUP = True
|
|
1289
1355
|
|
|
@@ -1418,7 +1484,7 @@ class SimCCSyscall(SimCC):
|
|
|
1418
1484
|
self.ERROR_REG.set_value(state, error_reg_val)
|
|
1419
1485
|
return expr
|
|
1420
1486
|
|
|
1421
|
-
def set_return_val(self, state, val, ty, **kwargs): # pylint:disable=arguments-differ
|
|
1487
|
+
def set_return_val(self, state, val, ty, **kwargs): # type:ignore # pylint:disable=arguments-differ
|
|
1422
1488
|
if self.ERROR_REG is not None:
|
|
1423
1489
|
val = self.linux_syscall_update_error_reg(state, val)
|
|
1424
1490
|
super().set_return_val(state, val, ty, **kwargs)
|
|
@@ -1556,6 +1622,7 @@ class SimCCSystemVAMD64(SimCC):
|
|
|
1556
1622
|
classification = self._classify(ty)
|
|
1557
1623
|
if any(cls == "MEMORY" for cls in classification):
|
|
1558
1624
|
assert all(cls == "MEMORY" for cls in classification)
|
|
1625
|
+
assert ty.size is not None
|
|
1559
1626
|
byte_size = ty.size // self.arch.byte_width
|
|
1560
1627
|
referenced_locs = [SimStackArg(offset, self.arch.bytes) for offset in range(0, byte_size, self.arch.bytes)]
|
|
1561
1628
|
referenced_loc = refine_locs_with_struct_type(self.arch, referenced_locs, ty)
|
|
@@ -1594,6 +1661,7 @@ class SimCCSystemVAMD64(SimCC):
|
|
|
1594
1661
|
if isinstance(ty, (SimTypeFloat,)):
|
|
1595
1662
|
return ["SSE"] + ["SSEUP"] * (nchunks - 1)
|
|
1596
1663
|
if isinstance(ty, (SimStruct, SimTypeFixedSizeArray, SimUnion)):
|
|
1664
|
+
assert ty.size is not None
|
|
1597
1665
|
if ty.size > 512:
|
|
1598
1666
|
return ["MEMORY"] * nchunks
|
|
1599
1667
|
flattened = self._flatten(ty)
|
|
@@ -1672,7 +1740,7 @@ class SimCCAMD64LinuxSyscall(SimCCSyscall):
|
|
|
1672
1740
|
CALLER_SAVED_REGS = ["rax", "rcx", "r11"]
|
|
1673
1741
|
|
|
1674
1742
|
@staticmethod
|
|
1675
|
-
def _match(arch, args, sp_delta): # pylint: disable=unused-argument
|
|
1743
|
+
def _match(arch, args, sp_delta): # type:ignore # pylint: disable=unused-argument
|
|
1676
1744
|
# doesn't appear anywhere but syscalls
|
|
1677
1745
|
return False
|
|
1678
1746
|
|
|
@@ -1804,6 +1872,7 @@ class SimCCARM(SimCC):
|
|
|
1804
1872
|
for suboffset, subsubty_list in subresult.items():
|
|
1805
1873
|
result[offset + suboffset] += subsubty_list
|
|
1806
1874
|
elif isinstance(ty, SimTypeFixedSizeArray):
|
|
1875
|
+
assert ty.elem_type.size is not None
|
|
1807
1876
|
subresult = self._flatten(ty.elem_type)
|
|
1808
1877
|
if subresult is None:
|
|
1809
1878
|
return None
|
|
@@ -2222,7 +2291,7 @@ class SimCCUnknown(SimCC):
|
|
|
2222
2291
|
"""
|
|
2223
2292
|
|
|
2224
2293
|
@staticmethod
|
|
2225
|
-
def _match(arch, args, sp_delta): # pylint: disable=unused-argument
|
|
2294
|
+
def _match(arch, args, sp_delta): # type:ignore # pylint: disable=unused-argument
|
|
2226
2295
|
# It always returns True
|
|
2227
2296
|
return True
|
|
2228
2297
|
|
|
@@ -2266,7 +2335,7 @@ CC: dict[str, dict[str, list[type[SimCC]]]] = {
|
|
|
2266
2335
|
"default": [SimCCCdecl],
|
|
2267
2336
|
"Linux": [SimCCCdecl],
|
|
2268
2337
|
"CGC": [SimCCCdecl],
|
|
2269
|
-
"Win32": [SimCCMicrosoftCdecl, SimCCMicrosoftFastcall],
|
|
2338
|
+
"Win32": [SimCCMicrosoftCdecl, SimCCMicrosoftFastcall, SimCCMicrosoftThiscall],
|
|
2270
2339
|
},
|
|
2271
2340
|
"ARMEL": {
|
|
2272
2341
|
"default": [SimCCARM],
|
angr/engines/light/engine.py
CHANGED
|
@@ -533,6 +533,7 @@ class SimEngineLightAIL(
|
|
|
533
533
|
def __init__(self, *args, **kwargs):
|
|
534
534
|
self._stmt_handlers: dict[str, Callable[[Any], StmtDataType]] = {
|
|
535
535
|
"Assignment": self._handle_stmt_Assignment,
|
|
536
|
+
"WeakAssignment": self._handle_stmt_WeakAssignment,
|
|
536
537
|
"Store": self._handle_stmt_Store,
|
|
537
538
|
"Jump": self._handle_stmt_Jump,
|
|
538
539
|
"ConditionalJump": self._handle_stmt_ConditionalJump,
|
|
@@ -697,6 +698,9 @@ class SimEngineLightAIL(
|
|
|
697
698
|
@abstractmethod
|
|
698
699
|
def _handle_stmt_Assignment(self, stmt: ailment.statement.Assignment) -> StmtDataType: ...
|
|
699
700
|
|
|
701
|
+
@abstractmethod
|
|
702
|
+
def _handle_stmt_WeakAssignment(self, stmt: ailment.statement.WeakAssignment) -> StmtDataType: ...
|
|
703
|
+
|
|
700
704
|
@abstractmethod
|
|
701
705
|
def _handle_stmt_Store(self, stmt: ailment.statement.Store) -> StmtDataType: ...
|
|
702
706
|
|
|
@@ -1006,6 +1010,9 @@ class SimEngineNostmtAIL(
|
|
|
1006
1010
|
def _handle_stmt_Assignment(self, stmt) -> StmtDataType | None:
|
|
1007
1011
|
pass
|
|
1008
1012
|
|
|
1013
|
+
def _handle_stmt_WeakAssignment(self, stmt) -> StmtDataType | None:
|
|
1014
|
+
pass
|
|
1015
|
+
|
|
1009
1016
|
def _handle_stmt_Store(self, stmt) -> StmtDataType | None:
|
|
1010
1017
|
pass
|
|
1011
1018
|
|