angr 9.2.178__cp310-abi3-win_amd64.whl → 9.2.179__cp310-abi3-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.

@@ -163,12 +163,30 @@ def switch_extract_cmp_bounds(
163
163
  def switch_extract_cmp_bounds_from_condition(cond: ailment.Expr.Expression) -> tuple[Any, int, int] | None:
164
164
  # TODO: Add more operations
165
165
  if isinstance(cond, ailment.Expr.BinaryOp):
166
- if cond.op in {"CmpLE", "CmpLT"}:
167
- if not (isinstance(cond.operands[1], ailment.Expr.Const) and isinstance(cond.operands[1].value, int)):
166
+ op = cond.op
167
+ op0, op1 = cond.operands
168
+ if not isinstance(op1, ailment.Expr.Const):
169
+ # swap them
170
+ match op:
171
+ case "CmpLE":
172
+ op = "CmpGE"
173
+ case "CmpLT":
174
+ op = "CmpGT"
175
+ case "CmpGE":
176
+ op = "CmpLE"
177
+ case "CmpGT":
178
+ op = "CmpLT"
179
+ case _:
180
+ # unsupported
181
+ return None
182
+ op0, op1 = op1, op0
183
+
184
+ if op in {"CmpLE", "CmpLT"}:
185
+ if not (isinstance(op1, ailment.Expr.Const) and isinstance(op1.value, int)):
168
186
  return None
169
- cmp_ub = cond.operands[1].value if cond.op == "CmpLE" else cond.operands[1].value - 1
187
+ cmp_ub = op1.value if op == "CmpLE" else op1.value - 1
170
188
  cmp_lb = 0
171
- cmp = cond.operands[0]
189
+ cmp = op0
172
190
  if (
173
191
  isinstance(cmp, ailment.Expr.BinaryOp)
174
192
  and cmp.op == "Sub"
@@ -180,15 +198,15 @@ def switch_extract_cmp_bounds_from_condition(cond: ailment.Expr.Expression) -> t
180
198
  cmp = cmp.operands[0]
181
199
  return cmp, cmp_lb, cmp_ub
182
200
 
183
- if cond.op in {"CmpGE", "CmpGT"}:
201
+ if op in {"CmpGE", "CmpGT"}:
184
202
  # We got the negated condition here
185
203
  # CmpGE -> CmpLT
186
204
  # CmpGT -> CmpLE
187
- if not (isinstance(cond.operands[1], ailment.Expr.Const) and isinstance(cond.operands[1].value, int)):
205
+ if not (isinstance(op1, ailment.Expr.Const) and isinstance(op1.value, int)):
188
206
  return None
189
- cmp_ub = cond.operands[1].value if cond.op == "CmpGT" else cond.operands[1].value - 1
207
+ cmp_ub = op1.value if op == "CmpGT" else op1.value - 1
190
208
  cmp_lb = 0
191
- cmp = cond.operands[0]
209
+ cmp = op0
192
210
  if (
193
211
  isinstance(cmp, ailment.Expr.BinaryOp)
194
212
  and cmp.op == "Sub"
@@ -34,7 +34,7 @@ class DisassemblyPiece:
34
34
  addr = None
35
35
  ident = float("nan")
36
36
 
37
- def render(self, formatting=None):
37
+ def render(self, formatting=None) -> list[str]:
38
38
  x = self._render(formatting)
39
39
  if len(x) == 1:
40
40
  return [self.highlight(x[0], formatting)]
@@ -73,7 +73,7 @@ class DisassemblyPiece:
73
73
  pass
74
74
  return string
75
75
 
76
- def __eq__(self, other):
76
+ def __eq__(self, other) -> bool:
77
77
  return False
78
78
 
79
79
 
@@ -175,7 +175,7 @@ class Instruction(DisassemblyPiece):
175
175
  self.arch = self.project.arch
176
176
  self.format = ""
177
177
  self.components = ()
178
- self.opcode = None
178
+ self.opcode: Opcode = None # type:ignore
179
179
  self.operands = []
180
180
 
181
181
  # the following members will be filled in after dissecting the instruction
@@ -261,7 +261,11 @@ class Instruction(DisassemblyPiece):
261
261
  if i > 0 and opr_pieces[i - 1] == "-":
262
262
  v = -v
263
263
  cur_operand.pop()
264
- cur_operand.append(Value(v, with_sign))
264
+ with_pound_sign = False
265
+ if i > 0 and opr_pieces[i - 1] == "#":
266
+ with_pound_sign = True
267
+ cur_operand.pop()
268
+ cur_operand.append(Value(v, with_sign, render_with_pound_sign=with_pound_sign))
265
269
  elif p[0].isalpha() and p in self.arch.registers:
266
270
  cur_operand.append(Register(p))
267
271
  else:
@@ -592,7 +596,7 @@ class Opcode(DisassemblyPiece):
592
596
  class Operand(DisassemblyPiece):
593
597
  def __init__(self, op_num, children, parentinsn):
594
598
  self.addr = parentinsn.addr
595
- self.children = children
599
+ self.children: list = children
596
600
  self.parentinsn = parentinsn
597
601
  self.op_num = op_num
598
602
  self.ident = (self.addr, "operand", self.op_num)
@@ -639,14 +643,33 @@ class Operand(DisassemblyPiece):
639
643
  operand = cls(op_num, children, parentinsn)
640
644
 
641
645
  # Post-processing
642
- if cls is MemoryOperand and parentinsn.arch.name in {"AMD64"} and len(operand.values) == 2:
646
+ if cls is MemoryOperand:
647
+ operand = Operand._post_process_memory_operand(parentinsn, operand)
648
+
649
+ return operand
650
+
651
+ @staticmethod
652
+ def _post_process_memory_operand(parentinsn: Instruction, operand: MemoryOperand) -> Operand:
653
+ archname = parentinsn.arch.name
654
+ if archname in {"AMD64", "ARM", "ARMEL", "ARMHF", "ARMCortexM"} and len(operand.values) == 2:
643
655
  op0, op1 = operand.values
644
656
  if type(op0) is Register and op0.is_ip and type(op1) is Value:
645
- # Indirect addressing in x86_64
657
+ # Indirect addressing in x86-64 and ARM
646
658
  # 400520 push [rip+0x200782] ==> 400520 push [0x600ca8]
647
- absolute_addr = parentinsn.addr + parentinsn.size + op1.val
659
+ # 80410e6 ldr r1, [pc, #0x98] ==> 80410e6 ldr r1, [0x8041182]
660
+ match archname:
661
+ case "AMD64":
662
+ absolute_addr = parentinsn.addr + parentinsn.size + op1.val
663
+ case "ARM" | "ARMEL" | "ARMHF" | "ARMCortexM":
664
+ if parentinsn.addr & 1:
665
+ # thumb mode
666
+ absolute_addr = (parentinsn.addr & 0xFFFF_FFFE) + 4 + op1.val
667
+ else:
668
+ # arm mode
669
+ absolute_addr = parentinsn.addr + 8 + op1.val
670
+ case _:
671
+ raise AngrTypeError(f"Unsupported architecture {archname} for post-processing memory operand.")
648
672
  return MemoryOperand(1, [*operand.prefix, "[", Value(absolute_addr, False), "]"], parentinsn)
649
-
650
673
  return operand
651
674
 
652
675
 
@@ -680,13 +703,15 @@ class MemoryOperand(Operand):
680
703
  # [ '[', Register, ']' ]
681
704
  # or
682
705
  # [ Value, '(', Register, ')' ]
706
+ # or
707
+ # [ Register, ",", Value]
683
708
 
684
709
  # it will be converted into more meaningful and Pythonic properties
685
710
 
686
711
  self.segment_selector = None
687
712
  self.prefix = []
688
713
  self.suffix_str = "" # could be arm pre index mark "!"
689
- self.values = []
714
+ self.values: list[str | DisassemblyPiece] = []
690
715
  self.offset = []
691
716
  # offset_location
692
717
  # - prefix: -0xff00($gp)
@@ -698,6 +723,10 @@ class MemoryOperand(Operand):
698
723
  # - curly: {rax+0x10}
699
724
  # - paren: (rax+0x10)
700
725
  self.values_style = "square"
726
+ # separator (between register and value)
727
+ # - "": rax+0x10
728
+ # - "comma": r0, #0x10
729
+ self.separator = ""
701
730
 
702
731
  try:
703
732
  if "[" in self.children:
@@ -711,8 +740,8 @@ class MemoryOperand(Operand):
711
740
  l.error("Failed to parse operand children %s. Please report to Fish.", self.children)
712
741
 
713
742
  # setup all dummy properties
714
- self.prefix = None
715
- self.values = None
743
+ self.prefix = []
744
+ self.values = []
716
745
 
717
746
  def _parse_memop_squarebracket(self):
718
747
  if self.children[0] != "[":
@@ -746,6 +775,27 @@ class MemoryOperand(Operand):
746
775
  raise ValueError
747
776
 
748
777
  self.values = self.children[square_bracket_pos + 1 : close_square_pos]
778
+ if len(self.values) >= 3 and self.values[1] == ",":
779
+ # arm style memory operand: [r0, #0x10], or [pc, r3, lsl #1]
780
+ self.separator = "comma"
781
+ # remove all commas and consolidate all remaining strings
782
+ new_values = []
783
+ last_item = None
784
+ for v in self.values:
785
+ if v == ",":
786
+ if last_item is not None:
787
+ new_values.append(last_item)
788
+ last_item = None
789
+ elif isinstance(v, str):
790
+ last_item = v if last_item is None else last_item + v
791
+ else:
792
+ if last_item is not None:
793
+ new_values.append(last_item)
794
+ last_item = None
795
+ new_values.append(v)
796
+ if last_item is not None:
797
+ new_values.append(last_item)
798
+ self.values = new_values
749
799
 
750
800
  def _parse_memop_paren(self):
751
801
  offset = []
@@ -801,7 +851,8 @@ class MemoryOperand(Operand):
801
851
  if custom_values_str is not None:
802
852
  value_str = custom_values_str
803
853
  else:
804
- value_str = "".join(x.render(formatting)[0] if not isinstance(x, (bytes, str)) else x for x in self.values)
854
+ sep = "," if self.separator == "comma" else ""
855
+ value_str = sep.join(x.render(formatting)[0] if not isinstance(x, str) else x for x in self.values)
805
856
 
806
857
  if values_style == "curly":
807
858
  left_paren, right_paren = "{", "}"
@@ -811,7 +862,7 @@ class MemoryOperand(Operand):
811
862
  left_paren, right_paren = "[", "]"
812
863
 
813
864
  if self.offset:
814
- offset_str = "".join(x.render(formatting)[0] if not isinstance(x, (bytes, str)) else x for x in self.offset)
865
+ offset_str = "".join(x.render(formatting)[0] if not isinstance(x, str) else x for x in self.offset)
815
866
 
816
867
  # combine values and offsets according to self.offset_location
817
868
  if self.offset_location == "prefix":
@@ -829,9 +880,7 @@ class MemoryOperand(Operand):
829
880
  prefix_str += " "
830
881
 
831
882
  if self.offset:
832
- offset_str = "".join(
833
- x.render(formatting)[0] if not isinstance(x, (bytes, str)) else x for x in self.offset
834
- )
883
+ offset_str = "".join(x.render(formatting)[0] if not isinstance(x, str) else x for x in self.offset)
835
884
 
836
885
  # combine values and offsets according to self.offset_location
837
886
  if self.offset_location == "prefix":
@@ -873,12 +922,14 @@ class Register(OperandPiece):
873
922
 
874
923
 
875
924
  class Value(OperandPiece):
876
- def __init__(self, val, render_with_sign):
925
+ def __init__(self, val, render_with_sign, render_with_pound_sign: bool = False):
877
926
  self.val = val
878
927
  self.render_with_sign = render_with_sign
928
+ self.render_with_pound_sign = render_with_pound_sign
879
929
 
880
930
  @property
881
931
  def project(self):
932
+ assert self.parentop is not None
882
933
  return self.parentop.parentinsn.project
883
934
 
884
935
  def __eq__(self, other):
@@ -888,26 +939,26 @@ class Value(OperandPiece):
888
939
  if formatting is not None:
889
940
  try:
890
941
  style = formatting["int_styles"][self.ident]
891
- if style[0] == "hex":
892
- if self.render_with_sign:
893
- return [f"{self.val:+#x}"]
894
- return [f"{self.val:#x}"]
895
- if style[0] == "dec":
896
- if self.render_with_sign:
897
- return [f"{self.val:+d}"]
898
- return [str(self.val)]
899
942
  if style[0] == "label":
900
943
  labeloffset = style[1]
901
944
  if labeloffset == 0:
902
945
  lbl = self.project.kb.labels[self.val]
903
946
  return [lbl]
904
- return [
905
- "{}{}{:#+x}".format(
906
- "+" if self.render_with_sign else "",
907
- self.project.kb.labels[self.val + labeloffset],
908
- labeloffset,
909
- )
910
- ]
947
+ s = "{}{}{:#+x}".format(
948
+ "+" if self.render_with_sign else "",
949
+ self.project.kb.labels[self.val + labeloffset],
950
+ labeloffset,
951
+ )
952
+ elif style[0] == "hex":
953
+ s = f"{self.val:+#x}" if self.render_with_sign else f"{self.val:#x}"
954
+ if self.render_with_pound_sign:
955
+ s = "#" + s
956
+ else: # "dec"
957
+ s = f"{self.val:+d}" if self.render_with_sign else str(self.val)
958
+
959
+ if self.render_with_pound_sign:
960
+ s = "#" + s
961
+ return [s]
911
962
  except KeyError:
912
963
  pass
913
964
 
@@ -927,9 +978,10 @@ class Value(OperandPiece):
927
978
  return [("+" if self.render_with_sign else "") + lbl]
928
979
  if func is not None:
929
980
  return [func.demangled_name]
930
- if self.render_with_sign:
931
- return [f"{self.val:+#x}"]
932
- return [f"{self.val:#x}"]
981
+ s = f"{self.val:+#x}" if self.render_with_sign else f"{self.val:#x}"
982
+ if self.render_with_pound_sign:
983
+ s = "#" + s
984
+ return [s]
933
985
 
934
986
 
935
987
  class Comment(DisassemblyPiece):
@@ -1079,10 +1131,11 @@ class Disassembly(Analysis):
1079
1131
  if irsb.statements is not None:
1080
1132
  if pcode is not None and isinstance(self.project.factory.default_engine, pcode.HeavyPcodeMixin):
1081
1133
  addr = None
1082
- for stmt_idx, op in enumerate(irsb._ops):
1134
+ for stmt_idx, op in enumerate(irsb._ops): # type:ignore
1083
1135
  if op.opcode == pypcode.OpCode.IMARK:
1084
1136
  addr = op.inputs[0].offset
1085
1137
  else:
1138
+ assert addr is not None
1086
1139
  addr_to_ops_map[addr].append(IROp(addr, stmt_idx, op, irsb))
1087
1140
  else:
1088
1141
  for seq, stmt in enumerate(irsb.statements):
@@ -1166,22 +1219,23 @@ class Disassembly(Analysis):
1166
1219
  buf = []
1167
1220
 
1168
1221
  if formatting is None:
1222
+ colors = (
1223
+ {
1224
+ "address": "gray",
1225
+ "bytes": "cyan",
1226
+ "edge": "yellow",
1227
+ Label: "bright_yellow",
1228
+ ConstantOperand: "cyan",
1229
+ MemoryOperand: "yellow",
1230
+ Comment: "gray",
1231
+ Hook: "green",
1232
+ }
1233
+ if ansi_color_enabled and color
1234
+ else {}
1235
+ )
1169
1236
  formatting = {
1170
- "colors": (
1171
- {
1172
- "address": "gray",
1173
- "bytes": "cyan",
1174
- "edge": "yellow",
1175
- Label: "bright_yellow",
1176
- ConstantOperand: "cyan",
1177
- MemoryOperand: "yellow",
1178
- Comment: "gray",
1179
- Hook: "green",
1180
- }
1181
- if ansi_color_enabled and color
1182
- else {}
1183
- ),
1184
- "format_callback": lambda item, s: ansi_color(s, formatting["colors"].get(type(item), None)),
1237
+ "colors": colors,
1238
+ "format_callback": lambda item, s: ansi_color(s, colors.get(type(item), None)),
1185
1239
  }
1186
1240
 
1187
1241
  def col(item: Any) -> str | None:
@@ -1234,12 +1288,14 @@ class Disassembly(Analysis):
1234
1288
  # Format the instruction's address, bytes, disassembly, and comment
1235
1289
  s_plain = format_address(item.addr, False)
1236
1290
  s = format_address(item.addr)
1291
+ bytes_column = 0
1237
1292
  if show_bytes:
1238
1293
  bytes_column = len(s_plain)
1239
1294
  s_plain += format_bytes(insn_bytes[0], False)
1240
1295
  s += format_bytes(insn_bytes[0])
1241
1296
  s_plain += item.render()[0]
1242
1297
  s += item.render(formatting)[0]
1298
+ comment_column = 0
1243
1299
  if comment is not None:
1244
1300
  comment_column = len(s_plain)
1245
1301
  s += format_comment(comment.text[0])
@@ -357,26 +357,27 @@ class ProximityGraphAnalysis(Analysis):
357
357
  def _handle_Call(
358
358
  stmt_idx: int, stmt: ailment.Stmt.Call, block: ailment.Block | None # pylint:disable=unused-argument
359
359
  ): # pylint:disable=unused-argument
360
- func_node = self.kb.functions[stmt.target.value]
361
- ref_at = {stmt.ins_addr}
362
-
363
- # extract arguments
364
- args = []
365
- if stmt.args:
366
- for arg in stmt.args:
367
- self._arg_handler(arg, args, string_refs)
368
-
369
- if (
370
- self._expand_funcs and func_node.addr in self._expand_funcs
371
- ): # pylint:disable=unsupported-membership-test
372
- new_node = FunctionProxiNode(func_node, ref_at=ref_at)
373
- if new_node not in to_expand:
374
- to_expand.append(new_node)
375
- else:
376
- new_node = CallProxiNode(func_node, ref_at=ref_at, args=tuple(args) if args is not None else None)
360
+ if isinstance(stmt.target, ailment.Expr.Const) and self.kb.functions.contains_addr(stmt.target.value):
361
+ func_node = self.kb.functions[stmt.target.value]
362
+ ref_at = {stmt.ins_addr}
363
+
364
+ # extract arguments
365
+ args = []
366
+ if stmt.args:
367
+ for arg in stmt.args:
368
+ self._arg_handler(arg, args, string_refs)
369
+
370
+ if (
371
+ self._expand_funcs and func_node.addr in self._expand_funcs
372
+ ): # pylint:disable=unsupported-membership-test
373
+ new_node = FunctionProxiNode(func_node, ref_at=ref_at)
374
+ if new_node not in to_expand:
375
+ to_expand.append(new_node)
376
+ else:
377
+ new_node = CallProxiNode(func_node, ref_at=ref_at, args=tuple(args) if args is not None else None)
377
378
 
378
- # stmt has been properly handled, add the proxi node to the list
379
- self.handled_stmts.append(new_node)
379
+ # stmt has been properly handled, add the proxi node to the list
380
+ self.handled_stmts.append(new_node)
380
381
 
381
382
  # This should have the same functionality as the previous handler
382
383
  def _handle_CallExpr(
angr/flirt/__init__.py CHANGED
@@ -26,6 +26,60 @@ LIBRARY_TO_SIGNATURES: dict[str, list[FlirtSignature]] = defaultdict(list)
26
26
  STRING_TO_LIBRARIES: dict[str, set[str]] = defaultdict(set)
27
27
 
28
28
 
29
+ def load_signature(sig_path: str, meta_path: str | None = None) -> tuple[str, FlirtSignature] | None:
30
+ """
31
+ Load a single FLIRT signature from a specific path.
32
+
33
+ :param sig_path: Location of the FLIRT signature.
34
+ :return: A FlirtSignature object if loading was successful, None otherwise.
35
+ """
36
+
37
+ # parse it
38
+ try:
39
+ with open(sig_path, "rb") as f:
40
+ sig_parsed = FlirtSignatureParsed.parse(f)
41
+ except FlirtSignatureError:
42
+ return None
43
+
44
+ # is there a meta data file?
45
+ if meta_path is not None and os.path.isfile(meta_path):
46
+ # yes!
47
+ with open(meta_path) as f:
48
+ meta = json.load(f)
49
+
50
+ arch = str(meta.get("arch", "Unknown"))
51
+ platform = str(meta.get("platform", "UnknownOS"))
52
+ os_name = meta.get("os", None)
53
+ os_version = meta.get("os_version", None)
54
+ compiler = meta.get("compiler", None)
55
+ compiler_version = meta.get("compiler_version", None)
56
+ unique_strings = meta.get("unique_strings", None)
57
+
58
+ else:
59
+ # nope... we need to extract information from the signature file
60
+ arch = flirt_arch_to_arch_name(sig_parsed.arch, sig_parsed.app_types)
61
+ platform = flirt_os_type_to_os_name(sig_parsed.os_types)
62
+ os_name = None
63
+ os_version = None
64
+ unique_strings = None
65
+ compiler = None
66
+ compiler_version = None
67
+
68
+ signature = FlirtSignature(
69
+ arch,
70
+ platform,
71
+ sig_parsed.libname,
72
+ sig_path,
73
+ unique_strings=unique_strings,
74
+ compiler=compiler,
75
+ compiler_version=compiler_version,
76
+ os_name=os_name,
77
+ os_version=os_version,
78
+ )
79
+
80
+ return arch, signature
81
+
82
+
29
83
  def load_signatures(path: str) -> None:
30
84
  """
31
85
  Recursively load all FLIRT signatures under a specific path.
@@ -40,52 +94,14 @@ def load_signatures(path: str) -> None:
40
94
  for root, _, filenames in os.walk(path):
41
95
  for filename in filenames:
42
96
  if filename.endswith(".sig"):
43
- # parse it
44
97
  sig_path = os.path.join(root, filename)
45
- try:
46
- with open(sig_path, "rb") as f:
47
- sig_parsed = FlirtSignatureParsed.parse(f)
48
- except FlirtSignatureError:
98
+ meta_path = os.path.join(root, filename[:-4] + ".meta")
99
+ r = load_signature(sig_path, meta_path=meta_path)
100
+ if r is None:
49
101
  _l.warning("Failed to load FLIRT signature file %s.", sig_path)
50
102
  continue
51
103
 
52
- # is there a meta data file?
53
- meta_path = os.path.join(root, filename[:-4] + ".meta")
54
- if os.path.isfile(meta_path):
55
- # yes!
56
- with open(meta_path) as f:
57
- meta = json.load(f)
58
-
59
- arch = str(meta.get("arch", "Unknown"))
60
- platform = str(meta.get("platform", "UnknownOS"))
61
- os_name = meta.get("os", None)
62
- os_version = meta.get("os_version", None)
63
- compiler = meta.get("compiler", None)
64
- compiler_version = meta.get("compiler_version", None)
65
- unique_strings = meta.get("unique_strings", None)
66
-
67
- else:
68
- # nope... we need to extract information from the signature file
69
- arch = flirt_arch_to_arch_name(sig_parsed.arch, sig_parsed.app_types)
70
- platform = flirt_os_type_to_os_name(sig_parsed.os_types)
71
- os_name = None
72
- os_version = None
73
- unique_strings = None
74
- compiler = None
75
- compiler_version = None
76
-
77
- signature = FlirtSignature(
78
- arch,
79
- platform,
80
- sig_parsed.libname,
81
- sig_path,
82
- unique_strings=unique_strings,
83
- compiler=compiler,
84
- compiler_version=compiler_version,
85
- os_name=os_name,
86
- os_version=os_version,
87
- )
88
-
104
+ arch, signature = r
89
105
  FLIRT_SIGNATURES_BY_ARCH[arch].append(signature)
90
106
 
91
107
  # fill in LIBRARY_TO_SIGNATURES and STRING_TO_LIBRARIES
@@ -95,3 +111,14 @@ def load_signatures(path: str) -> None:
95
111
  if sig.unique_strings:
96
112
  for us in sig.unique_strings:
97
113
  STRING_TO_LIBRARIES[us].add(sig.sig_name)
114
+
115
+
116
+ __all__ = (
117
+ "FLIRT_SIGNATURES_BY_ARCH",
118
+ "FS",
119
+ "LIBRARY_TO_SIGNATURES",
120
+ "STRING_TO_LIBRARIES",
121
+ "FlirtSignature",
122
+ "load_signature",
123
+ "load_signatures",
124
+ )
@@ -419,7 +419,8 @@ class LiveDefinitions:
419
419
  sp_v = sp_values.one_value()
420
420
  if sp_v is None:
421
421
  values = [v for v in next(iter(sp_values.values())) if self.get_stack_offset(v) is not None]
422
- assert len({self.get_stack_offset(v) for v in values}) == 1
422
+ if len({self.get_stack_offset(v) for v in values}) != 1:
423
+ return None
423
424
  return self.get_stack_offset(values[0])
424
425
 
425
426
  return self.get_stack_offset(sp_v)
angr/rustylib.pyd CHANGED
Binary file
angr/unicornlib.dll CHANGED
Binary file
angr/utils/types.py CHANGED
@@ -97,6 +97,8 @@ def dereference_simtype(
97
97
  continue
98
98
  if real_type is None:
99
99
  raise AngrMissingTypeError(f"Missing type {t.name}")
100
+ if t._arch is not None:
101
+ real_type = real_type.with_arch(t._arch)
100
102
  return dereference_simtype(real_type, type_collections, memo=memo)
101
103
 
102
104
  # the following code prepares a real_type SimType object that will be returned at the end of this method
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: angr
3
- Version: 9.2.178
3
+ Version: 9.2.179
4
4
  Summary: A multi-architecture binary analysis toolkit, with the ability to perform dynamic symbolic execution and various static analyses on binaries
5
5
  License: BSD-2-Clause
6
6
  Project-URL: Homepage, https://angr.io/
@@ -16,12 +16,12 @@ Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
17
  Requires-Dist: cxxheaderparser
18
18
  Requires-Dist: GitPython
19
- Requires-Dist: archinfo==9.2.178
19
+ Requires-Dist: archinfo==9.2.179
20
20
  Requires-Dist: cachetools
21
21
  Requires-Dist: capstone==5.0.3
22
22
  Requires-Dist: cffi>=1.14.0
23
- Requires-Dist: claripy==9.2.178
24
- Requires-Dist: cle==9.2.178
23
+ Requires-Dist: claripy==9.2.179
24
+ Requires-Dist: cle==9.2.179
25
25
  Requires-Dist: msgspec
26
26
  Requires-Dist: mulpyplexer
27
27
  Requires-Dist: networkx!=2.8.1,>=2.0
@@ -31,7 +31,7 @@ Requires-Dist: pycparser>=2.18
31
31
  Requires-Dist: pydemumble
32
32
  Requires-Dist: pyformlang
33
33
  Requires-Dist: pypcode<4.0,>=3.2.1
34
- Requires-Dist: pyvex==9.2.178
34
+ Requires-Dist: pyvex==9.2.179
35
35
  Requires-Dist: rich>=13.1.0
36
36
  Requires-Dist: sortedcontainers
37
37
  Requires-Dist: sympy
@@ -66,7 +66,7 @@ Project repository: https://github.com/angr/angr
66
66
 
67
67
  Documentation: https://docs.angr.io
68
68
 
69
- API Documentation: https://api.angr.io/en/latest/
69
+ API Documentation: https://docs.angr.io/en/latest/api.html
70
70
 
71
71
  ## What is angr?
72
72
 
@@ -80,7 +80,7 @@ angr is a suite of Python 3 libraries that let you load a binary and do a lot of
80
80
  - Value-set analysis (VSA)
81
81
  - Decompilation
82
82
 
83
- The most common angr operation is loading a binary: `p = angr.Project('/bin/bash')` If you do this in an enhanced REPL like IPython, you can use tab-autocomplete to browse the [top-level-accessible methods](https://docs.angr.io/docs/toplevel) and their docstrings.
83
+ The most common angr operation is loading a binary: `p = angr.Project('/bin/bash')` If you do this in an enhanced REPL like IPython, you can use tab-autocomplete to browse the [top-level-accessible methods](https://docs.angr.io/core-concepts/toplevel) and their docstrings.
84
84
 
85
85
  The short version of "how to install angr" is `mkvirtualenv --python=$(which python3) angr && python -m pip install angr`.
86
86
 
@@ -108,5 +108,5 @@ project.execute()
108
108
  - Documentation as [HTML](https://docs.angr.io/) and sources in the angr [Github repository](https://github.com/angr/angr/tree/master/docs)
109
109
  - Dive right in: [top-level-accessible methods](https://docs.angr.io/core-concepts/toplevel)
110
110
  - [Examples using angr to solve CTF challenges](https://docs.angr.io/examples).
111
- - [API Reference](https://angr.io/api-doc/)
111
+ - [API Reference](https://docs.angr.io/en/latest/api.html)
112
112
  - [awesome-angr repo](https://github.com/degrigis/awesome-angr)