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.

Files changed (91) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/analysis.py +3 -11
  3. angr/analyses/calling_convention/calling_convention.py +42 -2
  4. angr/analyses/calling_convention/fact_collector.py +5 -4
  5. angr/analyses/calling_convention/utils.py +1 -0
  6. angr/analyses/cfg/cfg_base.py +3 -59
  7. angr/analyses/cfg/cfg_emulated.py +17 -14
  8. angr/analyses/cfg/cfg_fast.py +68 -63
  9. angr/analyses/cfg/cfg_fast_soot.py +3 -3
  10. angr/analyses/decompiler/ail_simplifier.py +65 -32
  11. angr/analyses/decompiler/block_simplifier.py +20 -6
  12. angr/analyses/decompiler/callsite_maker.py +28 -18
  13. angr/analyses/decompiler/clinic.py +84 -17
  14. angr/analyses/decompiler/condition_processor.py +0 -21
  15. angr/analyses/decompiler/counters/call_counter.py +3 -0
  16. angr/analyses/decompiler/dephication/rewriting_engine.py +24 -2
  17. angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
  18. angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +15 -13
  19. angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +1 -1
  20. angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
  21. angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +165 -0
  22. angr/analyses/decompiler/optimization_passes/engine_base.py +11 -2
  23. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +17 -2
  24. angr/analyses/decompiler/optimization_passes/optimization_pass.py +10 -6
  25. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +99 -30
  26. angr/analyses/decompiler/peephole_optimizations/__init__.py +6 -0
  27. angr/analyses/decompiler/peephole_optimizations/base.py +43 -3
  28. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
  29. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +3 -0
  30. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +4 -1
  31. angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
  32. angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +69 -2
  33. angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +14 -0
  34. angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
  35. angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
  36. angr/analyses/decompiler/presets/fast.py +2 -0
  37. angr/analyses/decompiler/presets/full.py +2 -0
  38. angr/analyses/decompiler/ssailification/rewriting_engine.py +51 -4
  39. angr/analyses/decompiler/ssailification/ssailification.py +23 -3
  40. angr/analyses/decompiler/ssailification/traversal_engine.py +15 -1
  41. angr/analyses/decompiler/structured_codegen/c.py +146 -15
  42. angr/analyses/decompiler/structuring/phoenix.py +11 -3
  43. angr/analyses/decompiler/utils.py +6 -1
  44. angr/analyses/deobfuscator/api_obf_finder.py +5 -1
  45. angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
  46. angr/analyses/forward_analysis/visitors/graph.py +0 -8
  47. angr/analyses/identifier/runner.py +1 -1
  48. angr/analyses/reaching_definitions/function_handler.py +4 -4
  49. angr/analyses/reassembler.py +1 -1
  50. angr/analyses/s_reaching_definitions/s_rda_view.py +1 -0
  51. angr/analyses/stack_pointer_tracker.py +1 -1
  52. angr/analyses/static_hooker.py +11 -9
  53. angr/analyses/typehoon/lifter.py +20 -0
  54. angr/analyses/typehoon/simple_solver.py +42 -9
  55. angr/analyses/typehoon/translator.py +4 -1
  56. angr/analyses/typehoon/typeconsts.py +17 -6
  57. angr/analyses/typehoon/typehoon.py +21 -5
  58. angr/analyses/variable_recovery/engine_ail.py +52 -13
  59. angr/analyses/variable_recovery/engine_base.py +37 -12
  60. angr/analyses/variable_recovery/variable_recovery_fast.py +33 -2
  61. angr/calling_conventions.py +96 -27
  62. angr/engines/light/engine.py +7 -0
  63. angr/exploration_techniques/director.py +1 -1
  64. angr/knowledge_plugins/functions/function.py +109 -38
  65. angr/knowledge_plugins/functions/function_manager.py +9 -0
  66. angr/knowledge_plugins/functions/function_parser.py +9 -1
  67. angr/knowledge_plugins/functions/soot_function.py +1 -1
  68. angr/knowledge_plugins/key_definitions/key_definition_manager.py +1 -1
  69. angr/knowledge_plugins/propagations/states.py +5 -2
  70. angr/knowledge_plugins/variables/variable_manager.py +3 -3
  71. angr/lib/angr_native.dll +0 -0
  72. angr/procedures/definitions/__init__.py +15 -12
  73. angr/procedures/definitions/types_stl.py +22 -0
  74. angr/procedures/stubs/format_parser.py +1 -1
  75. angr/project.py +23 -29
  76. angr/protos/cfg_pb2.py +14 -25
  77. angr/protos/function_pb2.py +11 -22
  78. angr/protos/primitives_pb2.py +36 -47
  79. angr/protos/variables_pb2.py +28 -39
  80. angr/protos/xrefs_pb2.py +8 -19
  81. angr/sim_type.py +251 -146
  82. angr/simos/cgc.py +1 -1
  83. angr/simos/linux.py +5 -5
  84. angr/simos/windows.py +5 -5
  85. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -1
  86. {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/METADATA +9 -8
  87. {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/RECORD +91 -85
  88. {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/WHEEL +1 -1
  89. {angr-9.2.147.dist-info → angr-9.2.149.dist-info/licenses}/LICENSE +3 -0
  90. {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/entry_points.txt +0 -0
  91. {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
- # the constraint below is a default constraint that may conflict with more specific ones with different
460
- # sizes; we post-process at the very end of VRA to remove conflicting default constraints.
461
- self.state.add_type_constraint(typevars.Subtype(typevar, typeconsts.int_type(variable.size * 8)))
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
- variable = SimRegisterVariable(
981
- offset,
982
- size if force_variable_size is None else force_variable_size,
983
- ident=self.state.variable_manager[self.func_addr].next_variable_ident("register"),
984
- region=self.func_addr,
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, self.kb, call_info=call_info, vvar_to_vvar=self.vvar_to_vvar
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)
@@ -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, Sequence
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
- child_type = SimTypeArray(ty.pts_to) if type(arg.value) in (str, bytes, list) else ty.pts_to
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 type(arg) is str:
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
- if len(arg) > ty.length:
1013
- raise TypeError(f"String {arg!r} is too long for {ty}")
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 len(arg) > ty.length + 1:
1022
- raise TypeError(f"String {arg!r} is too long for {ty}")
1023
- arg = arg.ljust(ty.length + 1, b"\0")
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, (SimTypePointer, SimTypeReference)):
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 type(arg) is not SimStructValue:
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
- return claripy.BVV(arg.concrete_value, ty.size)
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 = (max(a.stack_offset for a in stack_args) // cls.ARCH().bytes + 1) if stack_args else 0
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: Sequence[SimFunctionArgument], sp_delta: int, platform: str = "Linux"
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],
@@ -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
 
@@ -71,7 +71,7 @@ class BaseGoal:
71
71
 
72
72
  block_id = cfg._generate_block_id(call_stack_suffix, state.addr, is_syscall)
73
73
 
74
- return cfg.get_node(block_id)
74
+ return cfg.model.get_node(block_id)
75
75
 
76
76
  @staticmethod
77
77
  def _dfs_edges(graph, source, max_steps=None):