angr 9.2.150__py3-none-win_amd64.whl → 9.2.153__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/calling_convention/calling_convention.py +17 -9
- angr/analyses/cfg/cfg_base.py +1 -1
- angr/analyses/cfg/cfg_fast.py +39 -0
- angr/analyses/decompiler/ail_simplifier.py +0 -1
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +39 -0
- angr/analyses/decompiler/clinic.py +118 -2
- angr/analyses/decompiler/dephication/rewriting_engine.py +38 -1
- angr/analyses/decompiler/optimization_passes/condition_constprop.py +6 -0
- angr/analyses/decompiler/optimization_passes/engine_base.py +5 -0
- angr/analyses/decompiler/peephole_optimizations/__init__.py +2 -0
- angr/analyses/decompiler/peephole_optimizations/cas_intrinsics.py +115 -0
- angr/analyses/decompiler/region_identifier.py +171 -119
- angr/analyses/decompiler/ssailification/rewriting_engine.py +37 -1
- angr/analyses/decompiler/ssailification/traversal_engine.py +10 -1
- angr/analyses/reaching_definitions/engine_ail.py +20 -0
- angr/analyses/s_propagator.py +28 -0
- angr/analyses/smc.py +3 -1
- angr/analyses/stack_pointer_tracker.py +2 -1
- angr/analyses/typehoon/simple_solver.py +143 -81
- angr/analyses/typehoon/typehoon.py +2 -1
- angr/analyses/variable_recovery/engine_ail.py +9 -0
- angr/engines/light/engine.py +7 -0
- angr/knowledge_plugins/functions/function.py +10 -4
- angr/lib/angr_native.dll +0 -0
- angr/storage/memory_mixins/clouseau_mixin.py +7 -1
- angr/utils/graph.py +10 -12
- angr/utils/ssa/__init__.py +6 -1
- {angr-9.2.150.dist-info → angr-9.2.153.dist-info}/METADATA +6 -6
- {angr-9.2.150.dist-info → angr-9.2.153.dist-info}/RECORD +34 -33
- {angr-9.2.150.dist-info → angr-9.2.153.dist-info}/WHEEL +1 -1
- {angr-9.2.150.dist-info → angr-9.2.153.dist-info}/entry_points.txt +0 -0
- {angr-9.2.150.dist-info → angr-9.2.153.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.150.dist-info → angr-9.2.153.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
import enum
|
|
4
4
|
from collections import defaultdict
|
|
5
|
+
from contextlib import suppress
|
|
5
6
|
import logging
|
|
6
7
|
|
|
7
8
|
import networkx
|
|
@@ -51,23 +52,6 @@ from .dfa import DFAConstraintSolver, EmptyEpsilonNFAError
|
|
|
51
52
|
_l = logging.getLogger(__name__)
|
|
52
53
|
|
|
53
54
|
|
|
54
|
-
PRIMITIVE_TYPES = {
|
|
55
|
-
TopType(),
|
|
56
|
-
Int(),
|
|
57
|
-
Int8(),
|
|
58
|
-
Int16(),
|
|
59
|
-
Int32(),
|
|
60
|
-
Int64(),
|
|
61
|
-
Pointer32(),
|
|
62
|
-
Pointer64(),
|
|
63
|
-
BottomType(),
|
|
64
|
-
Struct(),
|
|
65
|
-
Array(),
|
|
66
|
-
Float(),
|
|
67
|
-
Float32(),
|
|
68
|
-
Float64(),
|
|
69
|
-
}
|
|
70
|
-
|
|
71
55
|
Top_ = TopType()
|
|
72
56
|
Int_ = Int()
|
|
73
57
|
Int64_ = Int64()
|
|
@@ -83,6 +67,25 @@ Float_ = Float()
|
|
|
83
67
|
Float32_ = Float32()
|
|
84
68
|
Float64_ = Float64()
|
|
85
69
|
|
|
70
|
+
|
|
71
|
+
PRIMITIVE_TYPES = {
|
|
72
|
+
Top_,
|
|
73
|
+
Int_,
|
|
74
|
+
Int8_,
|
|
75
|
+
Int16_,
|
|
76
|
+
Int32_,
|
|
77
|
+
Int64_,
|
|
78
|
+
Pointer32_,
|
|
79
|
+
Pointer64_,
|
|
80
|
+
Bottom_,
|
|
81
|
+
Struct_,
|
|
82
|
+
Array_,
|
|
83
|
+
Float_,
|
|
84
|
+
Float32_,
|
|
85
|
+
Float64_,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
86
89
|
# lattice for 64-bit binaries
|
|
87
90
|
BASE_LATTICE_64 = networkx.DiGraph()
|
|
88
91
|
BASE_LATTICE_64.add_edge(Top_, Int_)
|
|
@@ -149,6 +152,24 @@ class SketchNode(SketchNodeBase):
|
|
|
149
152
|
def __hash__(self):
|
|
150
153
|
return hash((SketchNode, self.typevar))
|
|
151
154
|
|
|
155
|
+
@property
|
|
156
|
+
def size(self) -> int | None:
|
|
157
|
+
"""
|
|
158
|
+
Best-effort estimation of the size of the typevar (in bits). Returns None if we cannot determine.
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
if isinstance(self.typevar, DerivedTypeVariable):
|
|
162
|
+
last_label = self.typevar.labels[-1]
|
|
163
|
+
if isinstance(last_label, HasField) and last_label.bits != MAX_POINTSTO_BITS:
|
|
164
|
+
return last_label.bits
|
|
165
|
+
if isinstance(self.lower_bound, TypeConstant) and not isinstance(self.lower_bound, (TopType, BottomType)):
|
|
166
|
+
with suppress(NotImplementedError):
|
|
167
|
+
return self.lower_bound.size * 8
|
|
168
|
+
if isinstance(self.upper_bound, TypeConstant) and not isinstance(self.upper_bound, (TopType, BottomType)):
|
|
169
|
+
with suppress(NotImplementedError):
|
|
170
|
+
return self.upper_bound.size * 8
|
|
171
|
+
return None
|
|
172
|
+
|
|
152
173
|
|
|
153
174
|
class RecursiveRefNode(SketchNodeBase):
|
|
154
175
|
"""
|
|
@@ -433,9 +454,8 @@ class SimpleSolver:
|
|
|
433
454
|
if isinstance(tv, TypeVariable) and isinstance(sol, TypeConstant):
|
|
434
455
|
self.solution[tv] = sol
|
|
435
456
|
|
|
436
|
-
equ_classes, sketches, _ = self.solve()
|
|
437
457
|
self._solution_cache = {}
|
|
438
|
-
self.
|
|
458
|
+
self.solve()
|
|
439
459
|
for typevar in list(self._constraints):
|
|
440
460
|
self._convert_arrays(self._constraints[typevar])
|
|
441
461
|
|
|
@@ -448,6 +468,11 @@ class SimpleSolver:
|
|
|
448
468
|
- Build the constraint graph
|
|
449
469
|
- Collect all constraints
|
|
450
470
|
- Apply constraints to derive the lower and upper bounds
|
|
471
|
+
- Determine a solution for type variables with constraints
|
|
472
|
+
- Rewrite the constraint graph by replacing determined type variables with their solutions
|
|
473
|
+
- Solve repeatedly until all interesting type variables have solutions
|
|
474
|
+
|
|
475
|
+
By repeatedly solving until exhausting interesting type variables, we ensure the S-Trans rule is applied.
|
|
451
476
|
"""
|
|
452
477
|
|
|
453
478
|
prem_typevars = set(self._constraints) | self._typevars
|
|
@@ -476,11 +501,7 @@ class SimpleSolver:
|
|
|
476
501
|
elif isinstance(t, TypeVariable) and t in typevars:
|
|
477
502
|
constrained_typevars.add(t)
|
|
478
503
|
|
|
479
|
-
|
|
480
|
-
# TODO: Handle global variables
|
|
481
|
-
|
|
482
|
-
type_schemes = constraints
|
|
483
|
-
|
|
504
|
+
_, sketches = self.infer_shapes(typevars, constraints)
|
|
484
505
|
constraintset2tvs = defaultdict(set)
|
|
485
506
|
for idx, tv in enumerate(constrained_typevars):
|
|
486
507
|
_l.debug("Collecting constraints for type variable %r (%d/%d)", tv, idx + 1, len(constrained_typevars))
|
|
@@ -490,20 +511,43 @@ class SimpleSolver:
|
|
|
490
511
|
|
|
491
512
|
for idx, (constraint_subset, tvs) in enumerate(constraintset2tvs.items()):
|
|
492
513
|
_l.debug(
|
|
493
|
-
"Solving %d constraints for type variables %r (%d/%d)",
|
|
514
|
+
"Solving %d constraints for %d type variables %r (%d/%d)",
|
|
494
515
|
len(constraint_subset),
|
|
516
|
+
len(tvs),
|
|
495
517
|
tvs,
|
|
496
518
|
idx + 1,
|
|
497
519
|
len(constraintset2tvs),
|
|
498
520
|
)
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
primitive_constraints = self._generate_primitive_constraints(
|
|
521
|
+
|
|
522
|
+
while True:
|
|
523
|
+
base_constraint_graph = self._generate_constraint_graph(constraint_subset, tvs | PRIMITIVE_TYPES)
|
|
524
|
+
primitive_constraints = self._generate_primitive_constraints(tvs, base_constraint_graph)
|
|
525
|
+
tvs_with_primitive_constraints = set()
|
|
503
526
|
for primitive_constraint in primitive_constraints:
|
|
527
|
+
tv = self._typevar_from_primitive_constraint(primitive_constraint)
|
|
528
|
+
tvs_with_primitive_constraints.add(tv)
|
|
529
|
+
assert tv is not None, f"Cannot find type variable in primitive constraint {primitive_constraint}"
|
|
504
530
|
sketches[tv].add_constraint(primitive_constraint)
|
|
505
|
-
|
|
506
|
-
|
|
531
|
+
solutions = {}
|
|
532
|
+
self.determine(sketches, tvs_with_primitive_constraints, solutions)
|
|
533
|
+
_l.debug("Determined solutions for %d type variable(s).", len(tvs_with_primitive_constraints))
|
|
534
|
+
if not solutions:
|
|
535
|
+
break
|
|
536
|
+
|
|
537
|
+
self.solution |= solutions
|
|
538
|
+
|
|
539
|
+
tvs = {tv for tv in tvs if tv not in tvs_with_primitive_constraints}
|
|
540
|
+
if not tvs:
|
|
541
|
+
break
|
|
542
|
+
# rewrite existing constraints
|
|
543
|
+
new_constraint_subset = set()
|
|
544
|
+
for constraint in constraint_subset:
|
|
545
|
+
rewritten = self._rewrite_constraint(constraint, solutions)
|
|
546
|
+
new_constraint_subset.add(rewritten)
|
|
547
|
+
constraint_subset = new_constraint_subset
|
|
548
|
+
|
|
549
|
+
# set the solution for missing type vars to TOP
|
|
550
|
+
self.determine(sketches, set(sketches).difference(set(self.solution)), self.solution)
|
|
507
551
|
|
|
508
552
|
def infer_shapes(
|
|
509
553
|
self, typevars: set[TypeVariable], constraints: set[TypeConstraint]
|
|
@@ -593,7 +637,6 @@ class SimpleSolver:
|
|
|
593
637
|
non_primitive_endpoints: set[TypeVariable | DerivedTypeVariable],
|
|
594
638
|
constraint_graph,
|
|
595
639
|
) -> set[TypeConstraint]:
|
|
596
|
-
# FIXME: Extract interesting variables
|
|
597
640
|
constraints_0 = self._solve_constraints_between(constraint_graph, non_primitive_endpoints, PRIMITIVE_TYPES)
|
|
598
641
|
constraints_1 = self._solve_constraints_between(constraint_graph, PRIMITIVE_TYPES, non_primitive_endpoints)
|
|
599
642
|
return constraints_0 | constraints_1
|
|
@@ -612,6 +655,25 @@ class SimpleSolver:
|
|
|
612
655
|
# TODO: Other types of constraints?
|
|
613
656
|
return typevars
|
|
614
657
|
|
|
658
|
+
@staticmethod
|
|
659
|
+
def _typevar_from_primitive_constraint(constraint: TypeConstraint) -> TypeVariable | None:
|
|
660
|
+
if isinstance(constraint, Subtype):
|
|
661
|
+
if (
|
|
662
|
+
isinstance(constraint.sub_type, DerivedTypeVariable)
|
|
663
|
+
and type(constraint.sub_type.type_var) is TypeVariable
|
|
664
|
+
):
|
|
665
|
+
return constraint.sub_type.type_var
|
|
666
|
+
if type(constraint.sub_type) is TypeVariable:
|
|
667
|
+
return constraint.sub_type
|
|
668
|
+
if (
|
|
669
|
+
isinstance(constraint.super_type, DerivedTypeVariable)
|
|
670
|
+
and type(constraint.super_type.type_var) is TypeVariable
|
|
671
|
+
):
|
|
672
|
+
return constraint.super_type.type_var
|
|
673
|
+
if type(constraint.super_type) is TypeVariable:
|
|
674
|
+
return constraint.super_type
|
|
675
|
+
return None
|
|
676
|
+
|
|
615
677
|
@staticmethod
|
|
616
678
|
def _get_all_paths(
|
|
617
679
|
graph: networkx.DiGraph,
|
|
@@ -825,7 +887,6 @@ class SimpleSolver:
|
|
|
825
887
|
"""
|
|
826
888
|
|
|
827
889
|
graph = networkx.DiGraph()
|
|
828
|
-
constraints = self._get_transitive_subtype_constraints(constraints)
|
|
829
890
|
for constraint in constraints:
|
|
830
891
|
if isinstance(constraint, Subtype):
|
|
831
892
|
self._constraint_graph_add_edges(
|
|
@@ -836,33 +897,6 @@ class SimpleSolver:
|
|
|
836
897
|
self._constraint_graph_recall_forget_split(graph)
|
|
837
898
|
return graph
|
|
838
899
|
|
|
839
|
-
@staticmethod
|
|
840
|
-
def _get_transitive_subtype_constraints(constraints: set[TypeConstraint]) -> set[TypeConstraint]:
|
|
841
|
-
"""
|
|
842
|
-
Apply the S-Trans rule: a <: b, b <: c => a <: c
|
|
843
|
-
"""
|
|
844
|
-
tv2supertypes = defaultdict(set)
|
|
845
|
-
for constraint in constraints:
|
|
846
|
-
if isinstance(constraint, Subtype):
|
|
847
|
-
tv2supertypes[constraint.sub_type].add(constraint.super_type)
|
|
848
|
-
|
|
849
|
-
new_constraints = set()
|
|
850
|
-
while True:
|
|
851
|
-
changed = False
|
|
852
|
-
for subtype, supertypes in tv2supertypes.items():
|
|
853
|
-
supertypes_copy = set(supertypes)
|
|
854
|
-
for supertype in supertypes_copy:
|
|
855
|
-
if supertype in tv2supertypes:
|
|
856
|
-
for supertype_ in tv2supertypes[supertype]:
|
|
857
|
-
if supertype_ not in supertypes_copy:
|
|
858
|
-
changed = True
|
|
859
|
-
supertypes.add(supertype_)
|
|
860
|
-
new_constraints.add(Subtype(subtype, supertype_))
|
|
861
|
-
if not changed:
|
|
862
|
-
break
|
|
863
|
-
|
|
864
|
-
return constraints | new_constraints
|
|
865
|
-
|
|
866
900
|
@staticmethod
|
|
867
901
|
def _constraint_graph_add_recall_edges(graph: networkx.DiGraph, node: ConstraintGraphNode) -> None:
|
|
868
902
|
while True:
|
|
@@ -1004,12 +1038,7 @@ class SimpleSolver:
|
|
|
1004
1038
|
if typevar in typevar_set:
|
|
1005
1039
|
return True
|
|
1006
1040
|
if isinstance(typevar, Struct) and Struct_ in typevar_set:
|
|
1007
|
-
|
|
1008
|
-
return True
|
|
1009
|
-
return all(
|
|
1010
|
-
SimpleSolver._typevar_inside_set(field_typevar, typevar_set)
|
|
1011
|
-
for field_typevar in typevar.fields.values()
|
|
1012
|
-
)
|
|
1041
|
+
return True
|
|
1013
1042
|
if isinstance(typevar, Array) and Array_ in typevar_set:
|
|
1014
1043
|
return SimpleSolver._typevar_inside_set(typevar.element, typevar_set)
|
|
1015
1044
|
if isinstance(typevar, Pointer) and (Pointer32_ in typevar_set or Pointer64_ in typevar_set):
|
|
@@ -1110,31 +1139,47 @@ class SimpleSolver:
|
|
|
1110
1139
|
return Pointer64()
|
|
1111
1140
|
return t
|
|
1112
1141
|
|
|
1142
|
+
@staticmethod
|
|
1143
|
+
def _rewrite_constraint(constraint: TypeConstraint, solutions: dict) -> TypeConstraint:
|
|
1144
|
+
if isinstance(constraint, Subtype):
|
|
1145
|
+
replaced = False
|
|
1146
|
+
if isinstance(constraint.sub_type, TypeVariable) and constraint.sub_type in solutions:
|
|
1147
|
+
sub_type = solutions[constraint.sub_type]
|
|
1148
|
+
replaced = True
|
|
1149
|
+
else:
|
|
1150
|
+
sub_type = constraint.sub_type
|
|
1151
|
+
if isinstance(constraint.super_type, TypeVariable) and constraint.super_type in solutions:
|
|
1152
|
+
super_type = solutions[constraint.super_type]
|
|
1153
|
+
replaced = True
|
|
1154
|
+
else:
|
|
1155
|
+
super_type = constraint.super_type
|
|
1156
|
+
return Subtype(sub_type, super_type) if replaced else constraint
|
|
1157
|
+
return constraint
|
|
1158
|
+
|
|
1113
1159
|
def determine(
|
|
1114
1160
|
self,
|
|
1115
|
-
equivalent_classes: dict[TypeVariable, TypeVariable],
|
|
1116
1161
|
sketches,
|
|
1162
|
+
tvs,
|
|
1117
1163
|
solution: dict,
|
|
1118
1164
|
nodes: set[SketchNode] | None = None,
|
|
1119
1165
|
) -> None:
|
|
1120
1166
|
"""
|
|
1121
1167
|
Determine C-like types from sketches.
|
|
1122
1168
|
|
|
1123
|
-
:param equivalent_classes: A dictionary mapping each type variable from its representative in the equivalence
|
|
1124
|
-
class over ~.
|
|
1125
1169
|
:param sketches: A dictionary storing sketches for each type variable.
|
|
1126
1170
|
:param solution: The dictionary storing C-like types for each type variable. Output.
|
|
1127
1171
|
:param nodes: Optional. Nodes that should be considered in the sketch.
|
|
1128
1172
|
:return: None
|
|
1129
1173
|
"""
|
|
1130
|
-
for typevar, sketch in sketches.items():
|
|
1131
|
-
self._determine(equivalent_classes, typevar, sketch, solution, nodes=nodes)
|
|
1132
1174
|
|
|
1133
|
-
for
|
|
1134
|
-
|
|
1135
|
-
|
|
1175
|
+
for typevar in tvs:
|
|
1176
|
+
self._determine(typevar, sketches[typevar], solution, nodes=nodes)
|
|
1177
|
+
|
|
1178
|
+
for v, eq in self._equivalence.items():
|
|
1179
|
+
if v not in solution and eq in solution:
|
|
1180
|
+
solution[v] = solution[eq]
|
|
1136
1181
|
|
|
1137
|
-
def _determine(self,
|
|
1182
|
+
def _determine(self, the_typevar, sketch, solution: dict, nodes: set[SketchNode] | None = None):
|
|
1138
1183
|
"""
|
|
1139
1184
|
Return the solution from sketches
|
|
1140
1185
|
"""
|
|
@@ -1194,7 +1239,7 @@ class SimpleSolver:
|
|
|
1194
1239
|
for vals, out in [(func_inputs, input_args), (func_outputs, output_values)]:
|
|
1195
1240
|
for idx in range(max(vals) + 1):
|
|
1196
1241
|
if idx in vals:
|
|
1197
|
-
sol = self._determine(
|
|
1242
|
+
sol = self._determine(the_typevar, sketch, solution, nodes=vals[idx])
|
|
1198
1243
|
out.append(sol)
|
|
1199
1244
|
else:
|
|
1200
1245
|
out.append(None)
|
|
@@ -1290,7 +1335,7 @@ class SimpleSolver:
|
|
|
1290
1335
|
offset = sorted_offsets[i]
|
|
1291
1336
|
|
|
1292
1337
|
child_nodes = node_by_offset[offset]
|
|
1293
|
-
sol = self._determine(
|
|
1338
|
+
sol = self._determine(the_typevar, sketch, solution, nodes=child_nodes)
|
|
1294
1339
|
if isinstance(sol, TopType):
|
|
1295
1340
|
# make it an array if possible
|
|
1296
1341
|
elem_size = min(offset_to_sizes[offset])
|
|
@@ -1323,12 +1368,20 @@ class SimpleSolver:
|
|
|
1323
1368
|
lower_bound = Bottom_
|
|
1324
1369
|
upper_bound = Top_
|
|
1325
1370
|
|
|
1371
|
+
node_sizes = set()
|
|
1326
1372
|
for node in nodes:
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1373
|
+
node_size = node.size
|
|
1374
|
+
if node_size is not None:
|
|
1375
|
+
node_sizes.add(node_size)
|
|
1376
|
+
if len(node_sizes) > 1:
|
|
1377
|
+
# multi-sized reads - cannot converge to a reasonable type
|
|
1378
|
+
result = Bottom_
|
|
1379
|
+
else:
|
|
1380
|
+
for node in nodes:
|
|
1381
|
+
lower_bound = self.join(lower_bound, node.lower_bound)
|
|
1382
|
+
upper_bound = self.meet(upper_bound, node.upper_bound)
|
|
1383
|
+
result = lower_bound if not isinstance(lower_bound, BottomType) else upper_bound
|
|
1330
1384
|
|
|
1331
|
-
result = lower_bound if not isinstance(lower_bound, BottomType) else upper_bound
|
|
1332
1385
|
for node in nodes:
|
|
1333
1386
|
solution[node.typevar] = result
|
|
1334
1387
|
self._solution_cache[node.typevar] = result
|
|
@@ -1386,3 +1439,12 @@ class SimpleSolver:
|
|
|
1386
1439
|
if self.bits == 64:
|
|
1387
1440
|
return Pointer64
|
|
1388
1441
|
raise NotImplementedError(f"Unsupported bits {self.bits}")
|
|
1442
|
+
|
|
1443
|
+
@staticmethod
|
|
1444
|
+
def dump_constraint_graph(graph: networkx.DiGraph, filename: str) -> None:
|
|
1445
|
+
"""
|
|
1446
|
+
Dump the constraint graph to a file.
|
|
1447
|
+
"""
|
|
1448
|
+
from networkx.drawing.nx_agraph import write_dot # pylint:disable=import-outside-toplevel
|
|
1449
|
+
|
|
1450
|
+
write_dot(graph, filename)
|
|
@@ -100,7 +100,8 @@ class Typehoon(Analysis):
|
|
|
100
100
|
and not isinstance(type_.pts_to, SimTypeArray)
|
|
101
101
|
):
|
|
102
102
|
type_ = type_.pts_to
|
|
103
|
-
|
|
103
|
+
if type_ is not None:
|
|
104
|
+
type_candidates.append(type_)
|
|
104
105
|
|
|
105
106
|
# determine the best type - this logic can be made better!
|
|
106
107
|
if not type_candidates:
|
|
@@ -115,6 +115,15 @@ class SimEngineVRAIL(
|
|
|
115
115
|
tc = typevars.Subtype(src.typevar, dst.typevar)
|
|
116
116
|
self.state.add_type_constraint(tc)
|
|
117
117
|
|
|
118
|
+
def _handle_stmt_CAS(self, stmt) -> None:
|
|
119
|
+
self._expr(stmt.addr)
|
|
120
|
+
self._expr(stmt.data_lo)
|
|
121
|
+
if stmt.data_hi is not None:
|
|
122
|
+
self._expr(stmt.data_hi)
|
|
123
|
+
self._expr(stmt.expd_lo)
|
|
124
|
+
if stmt.expd_hi is not None:
|
|
125
|
+
self._expr(stmt.expd_hi)
|
|
126
|
+
|
|
118
127
|
def _handle_stmt_Store(self, stmt: ailment.Stmt.Store):
|
|
119
128
|
addr_r = self._expr_bv(stmt.addr)
|
|
120
129
|
data = self._expr(stmt.data)
|
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
|
+
"CAS": self._handle_stmt_CAS,
|
|
536
537
|
"WeakAssignment": self._handle_stmt_WeakAssignment,
|
|
537
538
|
"Store": self._handle_stmt_Store,
|
|
538
539
|
"Jump": self._handle_stmt_Jump,
|
|
@@ -698,6 +699,9 @@ class SimEngineLightAIL(
|
|
|
698
699
|
@abstractmethod
|
|
699
700
|
def _handle_stmt_Assignment(self, stmt: ailment.statement.Assignment) -> StmtDataType: ...
|
|
700
701
|
|
|
702
|
+
@abstractmethod
|
|
703
|
+
def _handle_stmt_CAS(self, stmt: ailment.statement.CAS) -> StmtDataType: ...
|
|
704
|
+
|
|
701
705
|
@abstractmethod
|
|
702
706
|
def _handle_stmt_WeakAssignment(self, stmt: ailment.statement.WeakAssignment) -> StmtDataType: ...
|
|
703
707
|
|
|
@@ -1013,6 +1017,9 @@ class SimEngineNostmtAIL(
|
|
|
1013
1017
|
def _handle_stmt_WeakAssignment(self, stmt) -> StmtDataType | None:
|
|
1014
1018
|
pass
|
|
1015
1019
|
|
|
1020
|
+
def _handle_stmt_CAS(self, stmt) -> StmtDataType | None:
|
|
1021
|
+
pass
|
|
1022
|
+
|
|
1016
1023
|
def _handle_stmt_Store(self, stmt) -> StmtDataType | None:
|
|
1017
1024
|
pass
|
|
1018
1025
|
|
|
@@ -127,7 +127,7 @@ class Function(Serializable):
|
|
|
127
127
|
self._retout_sites: set[BlockNode] = set()
|
|
128
128
|
# block nodes (basic block nodes) at whose ends the function terminates
|
|
129
129
|
# in theory, if everything works fine, endpoints == ret_sites | jumpout_sites | callout_sites
|
|
130
|
-
self._endpoints = defaultdict(set)
|
|
130
|
+
self._endpoints: defaultdict[str, set[BlockNode]] = defaultdict(set)
|
|
131
131
|
|
|
132
132
|
self._call_sites = {}
|
|
133
133
|
self.addr = addr
|
|
@@ -1358,7 +1358,7 @@ class Function(Serializable):
|
|
|
1358
1358
|
return
|
|
1359
1359
|
|
|
1360
1360
|
graph = self.transition_graph
|
|
1361
|
-
end_addresses = defaultdict(list)
|
|
1361
|
+
end_addresses: defaultdict[int, list[BlockNode]] = defaultdict(list)
|
|
1362
1362
|
|
|
1363
1363
|
for block in self.nodes:
|
|
1364
1364
|
if isinstance(block, BlockNode):
|
|
@@ -1456,7 +1456,13 @@ class Function(Serializable):
|
|
|
1456
1456
|
)
|
|
1457
1457
|
else:
|
|
1458
1458
|
# We gotta create a new one
|
|
1459
|
-
l.error("normalize(): Please report it to Fish
|
|
1459
|
+
l.error("normalize(): Please report it to Fish.")
|
|
1460
|
+
|
|
1461
|
+
# update endpoints
|
|
1462
|
+
for sortset in self._endpoints.values():
|
|
1463
|
+
if n in sortset:
|
|
1464
|
+
sortset.remove(n)
|
|
1465
|
+
sortset.add(smallest_node)
|
|
1460
1466
|
|
|
1461
1467
|
end_addresses[end_addr] = [smallest_node]
|
|
1462
1468
|
|
|
@@ -1680,7 +1686,7 @@ class Function(Serializable):
|
|
|
1680
1686
|
n = separator
|
|
1681
1687
|
if must_disambiguate_by_addr:
|
|
1682
1688
|
n += hex(self.addr) + separator
|
|
1683
|
-
elif self.binary is not self.project.loader.main_object:
|
|
1689
|
+
elif self.binary is not self.project.loader.main_object and self.binary_name is not None:
|
|
1684
1690
|
n += self.binary_name + separator
|
|
1685
1691
|
return n + (display_name or self.name)
|
|
1686
1692
|
|
angr/lib/angr_native.dll
CHANGED
|
Binary file
|
|
@@ -68,6 +68,7 @@ class InspectMixinHigh(MemoryMixin):
|
|
|
68
68
|
if not inspect or not self.state.supports_inspect:
|
|
69
69
|
return super().load(addr, size=size, condition=condition, endness=endness, inspect=inspect, **kwargs)
|
|
70
70
|
|
|
71
|
+
r = None
|
|
71
72
|
if self.category == "reg":
|
|
72
73
|
self.state._inspect(
|
|
73
74
|
"reg_read",
|
|
@@ -76,7 +77,9 @@ class InspectMixinHigh(MemoryMixin):
|
|
|
76
77
|
reg_read_length=size,
|
|
77
78
|
reg_read_condition=condition,
|
|
78
79
|
reg_read_endness=endness,
|
|
80
|
+
reg_read_expr=None,
|
|
79
81
|
)
|
|
82
|
+
r = self.state._inspect_getattr("reg_read_expr", None)
|
|
80
83
|
addr = self.state._inspect_getattr("reg_read_offset", addr)
|
|
81
84
|
size = self.state._inspect_getattr("reg_read_length", size)
|
|
82
85
|
condition = self.state._inspect_getattr("reg_read_condition", condition)
|
|
@@ -89,13 +92,16 @@ class InspectMixinHigh(MemoryMixin):
|
|
|
89
92
|
mem_read_length=size,
|
|
90
93
|
mem_read_condition=condition,
|
|
91
94
|
mem_read_endness=endness,
|
|
95
|
+
mem_read_expr=None,
|
|
92
96
|
)
|
|
97
|
+
r = self.state._inspect_getattr("mem_read_expr", None)
|
|
93
98
|
addr = self.state._inspect_getattr("mem_read_address", addr)
|
|
94
99
|
size = self.state._inspect_getattr("mem_read_length", size)
|
|
95
100
|
condition = self.state._inspect_getattr("mem_read_condition", condition)
|
|
96
101
|
endness = self.state._inspect_getattr("mem_read_endness", endness)
|
|
97
102
|
|
|
98
|
-
r
|
|
103
|
+
if r is None:
|
|
104
|
+
r = super().load(addr, size=size, condition=condition, endness=endness, inspect=inspect, **kwargs)
|
|
99
105
|
|
|
100
106
|
if self.category == "mem":
|
|
101
107
|
self.state._inspect(
|
angr/utils/graph.py
CHANGED
|
@@ -734,13 +734,18 @@ class GraphUtils:
|
|
|
734
734
|
|
|
735
735
|
# find all strongly connected components in the graph
|
|
736
736
|
sccs = [scc for scc in networkx.strongly_connected_components(graph) if len(scc) > 1]
|
|
737
|
+
comp_indices = {}
|
|
738
|
+
for i, scc in enumerate(sccs):
|
|
739
|
+
for node in scc:
|
|
740
|
+
if node not in comp_indices:
|
|
741
|
+
comp_indices[node] = i
|
|
737
742
|
|
|
738
743
|
# collapse all strongly connected components
|
|
739
744
|
for src, dst in sorted(graph.edges(), key=GraphUtils._sort_edge):
|
|
740
|
-
scc_index =
|
|
745
|
+
scc_index = comp_indices.get(src)
|
|
741
746
|
if scc_index is not None:
|
|
742
747
|
src = SCCPlaceholder(scc_index)
|
|
743
|
-
scc_index =
|
|
748
|
+
scc_index = comp_indices.get(dst)
|
|
744
749
|
if scc_index is not None:
|
|
745
750
|
dst = SCCPlaceholder(scc_index)
|
|
746
751
|
|
|
@@ -781,13 +786,6 @@ class GraphUtils:
|
|
|
781
786
|
return ordered_nodes
|
|
782
787
|
return [n for n in ordered_nodes if n in set(nodes)]
|
|
783
788
|
|
|
784
|
-
@staticmethod
|
|
785
|
-
def _components_index_node(components, node):
|
|
786
|
-
for i, comp in enumerate(components):
|
|
787
|
-
if node in comp:
|
|
788
|
-
return i
|
|
789
|
-
return None
|
|
790
|
-
|
|
791
789
|
@staticmethod
|
|
792
790
|
def _append_scc(
|
|
793
791
|
graph: networkx.DiGraph,
|
|
@@ -810,9 +808,9 @@ class GraphUtils:
|
|
|
810
808
|
|
|
811
809
|
if loop_head_candidates is not None:
|
|
812
810
|
# find the first node that appears in loop_heads
|
|
813
|
-
|
|
811
|
+
loop_head_candidates_set = set(loop_head_candidates)
|
|
814
812
|
for n in scc:
|
|
815
|
-
if n in
|
|
813
|
+
if n in loop_head_candidates_set:
|
|
816
814
|
loop_head = n
|
|
817
815
|
break
|
|
818
816
|
|
|
@@ -844,7 +842,7 @@ class GraphUtils:
|
|
|
844
842
|
# pick the first one
|
|
845
843
|
loop_head = sorted(scc, key=GraphUtils._sort_node)[0]
|
|
846
844
|
|
|
847
|
-
subgraph: networkx.DiGraph = graph.subgraph(scc).copy()
|
|
845
|
+
subgraph: networkx.DiGraph = graph.subgraph(scc).copy() # type: ignore
|
|
848
846
|
for src, _ in list(subgraph.in_edges(loop_head)):
|
|
849
847
|
subgraph.remove_edge(src, loop_head)
|
|
850
848
|
|
angr/utils/ssa/__init__.py
CHANGED
|
@@ -8,7 +8,7 @@ import networkx
|
|
|
8
8
|
import archinfo
|
|
9
9
|
from ailment import Expression, Block
|
|
10
10
|
from ailment.expression import VirtualVariable, Const, Phi, Tmp, Load, Register, StackBaseOffset, DirtyExpression, ITE
|
|
11
|
-
from ailment.statement import Statement, Assignment, Call, Store
|
|
11
|
+
from ailment.statement import Statement, Assignment, Call, Store, CAS
|
|
12
12
|
from ailment.block_walker import AILBlockWalkerBase
|
|
13
13
|
|
|
14
14
|
from angr.knowledge_plugins.key_definitions import atoms
|
|
@@ -126,6 +126,11 @@ def get_tmp_deflocs(blocks) -> dict[CodeLocation, dict[atoms.Tmp, int]]:
|
|
|
126
126
|
for stmt_idx, stmt in enumerate(block.statements):
|
|
127
127
|
if isinstance(stmt, Assignment) and isinstance(stmt.dst, Tmp):
|
|
128
128
|
tmp_to_loc[codeloc][atoms.Tmp(stmt.dst.tmp_idx, stmt.dst.bits)] = stmt_idx
|
|
129
|
+
if isinstance(stmt, CAS):
|
|
130
|
+
if isinstance(stmt.old_lo, Tmp):
|
|
131
|
+
tmp_to_loc[codeloc][atoms.Tmp(stmt.old_lo.tmp_idx, stmt.old_lo.bits)] = stmt_idx
|
|
132
|
+
if stmt.old_hi is not None and isinstance(stmt.old_hi, Tmp):
|
|
133
|
+
tmp_to_loc[codeloc][atoms.Tmp(stmt.old_hi.tmp_idx, stmt.old_hi.bits)] = stmt_idx
|
|
129
134
|
|
|
130
135
|
return tmp_to_loc
|
|
131
136
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: angr
|
|
3
|
-
Version: 9.2.
|
|
3
|
+
Version: 9.2.153
|
|
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/
|
|
@@ -17,13 +17,13 @@ Description-Content-Type: text/markdown
|
|
|
17
17
|
License-File: LICENSE
|
|
18
18
|
Requires-Dist: cxxheaderparser
|
|
19
19
|
Requires-Dist: GitPython
|
|
20
|
-
Requires-Dist: ailment==9.2.
|
|
21
|
-
Requires-Dist: archinfo==9.2.
|
|
20
|
+
Requires-Dist: ailment==9.2.153
|
|
21
|
+
Requires-Dist: archinfo==9.2.153
|
|
22
22
|
Requires-Dist: cachetools
|
|
23
23
|
Requires-Dist: capstone==5.0.3
|
|
24
24
|
Requires-Dist: cffi>=1.14.0
|
|
25
|
-
Requires-Dist: claripy==9.2.
|
|
26
|
-
Requires-Dist: cle==9.2.
|
|
25
|
+
Requires-Dist: claripy==9.2.153
|
|
26
|
+
Requires-Dist: cle==9.2.153
|
|
27
27
|
Requires-Dist: mulpyplexer
|
|
28
28
|
Requires-Dist: networkx!=2.8.1,>=2.0
|
|
29
29
|
Requires-Dist: protobuf>=5.28.2
|
|
@@ -31,7 +31,7 @@ Requires-Dist: psutil
|
|
|
31
31
|
Requires-Dist: pycparser>=2.18
|
|
32
32
|
Requires-Dist: pydemumble
|
|
33
33
|
Requires-Dist: pyformlang
|
|
34
|
-
Requires-Dist: pyvex==9.2.
|
|
34
|
+
Requires-Dist: pyvex==9.2.153
|
|
35
35
|
Requires-Dist: rich>=13.1.0
|
|
36
36
|
Requires-Dist: sortedcontainers
|
|
37
37
|
Requires-Dist: sympy
|