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.
- angr/__init__.py +1 -1
- angr/analyses/cfg/cfb.py +11 -0
- angr/analyses/decompiler/ail_simplifier.py +1 -1
- angr/analyses/decompiler/clinic.py +9 -3
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +38 -18
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +10 -4
- angr/analyses/decompiler/structured_codegen/c.py +54 -12
- angr/analyses/decompiler/structuring/phoenix.py +129 -64
- angr/analyses/decompiler/utils.py +26 -8
- angr/analyses/disassembly.py +108 -52
- angr/analyses/proximity_graph.py +20 -19
- angr/flirt/__init__.py +69 -42
- angr/knowledge_plugins/key_definitions/live_definitions.py +2 -1
- angr/rustylib.pyd +0 -0
- angr/unicornlib.dll +0 -0
- angr/utils/types.py +2 -0
- {angr-9.2.178.dist-info → angr-9.2.179.dist-info}/METADATA +8 -8
- {angr-9.2.178.dist-info → angr-9.2.179.dist-info}/RECORD +22 -22
- {angr-9.2.178.dist-info → angr-9.2.179.dist-info}/WHEEL +0 -0
- {angr-9.2.178.dist-info → angr-9.2.179.dist-info}/entry_points.txt +0 -0
- {angr-9.2.178.dist-info → angr-9.2.179.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.178.dist-info → angr-9.2.179.dist-info}/top_level.txt +0 -0
|
@@ -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
|
-
|
|
167
|
-
|
|
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 =
|
|
187
|
+
cmp_ub = op1.value if op == "CmpLE" else op1.value - 1
|
|
170
188
|
cmp_lb = 0
|
|
171
|
-
cmp =
|
|
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
|
|
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(
|
|
205
|
+
if not (isinstance(op1, ailment.Expr.Const) and isinstance(op1.value, int)):
|
|
188
206
|
return None
|
|
189
|
-
cmp_ub =
|
|
207
|
+
cmp_ub = op1.value if op == "CmpGT" else op1.value - 1
|
|
190
208
|
cmp_lb = 0
|
|
191
|
-
cmp =
|
|
209
|
+
cmp = op0
|
|
192
210
|
if (
|
|
193
211
|
isinstance(cmp, ailment.Expr.BinaryOp)
|
|
194
212
|
and cmp.op == "Sub"
|
angr/analyses/disassembly.py
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
657
|
+
# Indirect addressing in x86-64 and ARM
|
|
646
658
|
# 400520 push [rip+0x200782] ==> 400520 push [0x600ca8]
|
|
647
|
-
|
|
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 =
|
|
715
|
-
self.values =
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
905
|
-
"
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
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
|
-
|
|
932
|
-
|
|
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])
|
angr/analyses/proximity_graph.py
CHANGED
|
@@ -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
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
to_expand
|
|
375
|
-
|
|
376
|
-
|
|
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
|
-
|
|
379
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
24
|
-
Requires-Dist: cle==9.2.
|
|
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.
|
|
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://
|
|
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/
|
|
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
|
|
111
|
+
- [API Reference](https://docs.angr.io/en/latest/api.html)
|
|
112
112
|
- [awesome-angr repo](https://github.com/degrigis/awesome-angr)
|