angr 9.2.127__py3-none-manylinux2014_aarch64.whl → 9.2.129__py3-none-manylinux2014_aarch64.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/decompiler/clinic.py +22 -2
- angr/analyses/decompiler/decompiler.py +18 -4
- angr/analyses/decompiler/graph_region.py +3 -6
- angr/analyses/decompiler/label_collector.py +32 -0
- angr/analyses/decompiler/optimization_passes/__init__.py +3 -0
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +6 -3
- angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +41 -3
- angr/analyses/decompiler/optimization_passes/switch_reused_entry_rewriter.py +102 -0
- angr/analyses/decompiler/presets/basic.py +2 -0
- angr/analyses/decompiler/presets/fast.py +2 -0
- angr/analyses/decompiler/presets/full.py +2 -0
- angr/analyses/decompiler/region_identifier.py +8 -8
- angr/analyses/decompiler/structuring/phoenix.py +131 -31
- angr/analyses/decompiler/structuring/recursive_structurer.py +3 -1
- angr/analyses/decompiler/structuring/structurer_base.py +33 -1
- {angr-9.2.127.dist-info → angr-9.2.129.dist-info}/METADATA +6 -6
- {angr-9.2.127.dist-info → angr-9.2.129.dist-info}/RECORD +22 -20
- {angr-9.2.127.dist-info → angr-9.2.129.dist-info}/WHEEL +1 -1
- {angr-9.2.127.dist-info → angr-9.2.129.dist-info}/LICENSE +0 -0
- {angr-9.2.127.dist-info → angr-9.2.129.dist-info}/entry_points.txt +0 -0
- {angr-9.2.127.dist-info → angr-9.2.129.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
|
@@ -113,6 +113,8 @@ class Clinic(Analysis):
|
|
|
113
113
|
vvar_id_start: int = 0,
|
|
114
114
|
optimization_scratch: dict[str, Any] | None = None,
|
|
115
115
|
desired_variables: set[str] | None = None,
|
|
116
|
+
force_loop_single_exit: bool = True,
|
|
117
|
+
complete_successors: bool = False,
|
|
116
118
|
):
|
|
117
119
|
if not func.normalized and mode == ClinicMode.DECOMPILE:
|
|
118
120
|
raise ValueError("Decompilation must work on normalized function graphs.")
|
|
@@ -157,6 +159,8 @@ class Clinic(Analysis):
|
|
|
157
159
|
self._inlined_counts = {} if inlined_counts is None else inlined_counts
|
|
158
160
|
self._inlining_parents = inlining_parents or ()
|
|
159
161
|
self._desired_variables = desired_variables
|
|
162
|
+
self._force_loop_single_exit = force_loop_single_exit
|
|
163
|
+
self._complete_successors = complete_successors
|
|
160
164
|
|
|
161
165
|
self._register_save_areas_removed: bool = False
|
|
162
166
|
|
|
@@ -333,6 +337,7 @@ class Clinic(Analysis):
|
|
|
333
337
|
optimization_passes=[StackCanarySimplifier],
|
|
334
338
|
sp_shift=self._max_stack_depth,
|
|
335
339
|
vvar_id_start=self.vvar_id_start,
|
|
340
|
+
fail_fast=self._fail_fast,
|
|
336
341
|
)
|
|
337
342
|
self.vvar_id_start = callee_clinic.vvar_id_start + 1
|
|
338
343
|
self._max_stack_depth = callee_clinic._max_stack_depth
|
|
@@ -787,7 +792,7 @@ class Clinic(Analysis):
|
|
|
787
792
|
|
|
788
793
|
# case 2: the callee is a SimProcedure
|
|
789
794
|
if target_func.is_simprocedure:
|
|
790
|
-
cc = self.project.analyses.CallingConvention(target_func)
|
|
795
|
+
cc = self.project.analyses.CallingConvention(target_func, fail_fast=self._fail_fast)
|
|
791
796
|
if cc.cc is not None and cc.prototype is not None:
|
|
792
797
|
target_func.calling_convention = cc.cc
|
|
793
798
|
target_func.prototype = cc.prototype
|
|
@@ -795,7 +800,7 @@ class Clinic(Analysis):
|
|
|
795
800
|
|
|
796
801
|
# case 3: the callee is a PLT function
|
|
797
802
|
if target_func.is_plt:
|
|
798
|
-
cc = self.project.analyses.CallingConvention(target_func)
|
|
803
|
+
cc = self.project.analyses.CallingConvention(target_func, fail_fast=self._fail_fast)
|
|
799
804
|
if cc.cc is not None and cc.prototype is not None:
|
|
800
805
|
target_func.calling_convention = cc.cc
|
|
801
806
|
target_func.prototype = cc.prototype
|
|
@@ -834,6 +839,7 @@ class Clinic(Analysis):
|
|
|
834
839
|
callsite_block_addr=callsite.addr,
|
|
835
840
|
callsite_insn_addr=callsite_ins_addr,
|
|
836
841
|
func_graph=func_graph,
|
|
842
|
+
fail_fast=self._fail_fast,
|
|
837
843
|
)
|
|
838
844
|
|
|
839
845
|
if cc.cc is not None and cc.prototype is not None:
|
|
@@ -864,6 +870,7 @@ class Clinic(Analysis):
|
|
|
864
870
|
# finally, recover the calling convention of the current function
|
|
865
871
|
if self.function.prototype is None or self.function.calling_convention is None:
|
|
866
872
|
self.project.analyses.CompleteCallingConventions(
|
|
873
|
+
fail_fast=self._fail_fast,
|
|
867
874
|
recover_variables=True,
|
|
868
875
|
prioritize_func_addrs=[self.function.addr],
|
|
869
876
|
skip_other_funcs=True,
|
|
@@ -896,6 +903,7 @@ class Clinic(Analysis):
|
|
|
896
903
|
spt = self.project.analyses.StackPointerTracker(
|
|
897
904
|
self.function,
|
|
898
905
|
regs,
|
|
906
|
+
fail_fast=self._fail_fast,
|
|
899
907
|
track_memory=self._sp_tracker_track_memory,
|
|
900
908
|
cross_insn_opt=False,
|
|
901
909
|
initial_reg_values=initial_reg_values,
|
|
@@ -1130,6 +1138,7 @@ class Clinic(Analysis):
|
|
|
1130
1138
|
simp = self.project.analyses.AILBlockSimplifier(
|
|
1131
1139
|
ail_block,
|
|
1132
1140
|
self.function.addr,
|
|
1141
|
+
fail_fast=self._fail_fast,
|
|
1133
1142
|
remove_dead_memdefs=remove_dead_memdefs,
|
|
1134
1143
|
stack_pointer_tracker=stack_pointer_tracker,
|
|
1135
1144
|
peephole_optimizations=self.peephole_optimizations,
|
|
@@ -1201,6 +1210,7 @@ class Clinic(Analysis):
|
|
|
1201
1210
|
|
|
1202
1211
|
simp = self.project.analyses.AILSimplifier(
|
|
1203
1212
|
self.function,
|
|
1213
|
+
fail_fast=self._fail_fast,
|
|
1204
1214
|
func_graph=ail_graph,
|
|
1205
1215
|
remove_dead_memdefs=remove_dead_memdefs,
|
|
1206
1216
|
unify_variables=unify_variables,
|
|
@@ -1259,6 +1269,8 @@ class Clinic(Analysis):
|
|
|
1259
1269
|
vvar_id_start=self.vvar_id_start,
|
|
1260
1270
|
entry_node_addr=self.entry_node_addr,
|
|
1261
1271
|
scratch=self.optimization_scratch,
|
|
1272
|
+
force_loop_single_exit=self._force_loop_single_exit,
|
|
1273
|
+
complete_successors=self._complete_successors,
|
|
1262
1274
|
**kwargs,
|
|
1263
1275
|
)
|
|
1264
1276
|
if a.out_graph:
|
|
@@ -1342,6 +1354,7 @@ class Clinic(Analysis):
|
|
|
1342
1354
|
ssailification = self.project.analyses.Ssailification(
|
|
1343
1355
|
self.function,
|
|
1344
1356
|
ail_graph,
|
|
1357
|
+
fail_fast=self._fail_fast,
|
|
1345
1358
|
entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
|
|
1346
1359
|
ail_manager=self._ail_manager,
|
|
1347
1360
|
ssa_stackvars=False,
|
|
@@ -1355,6 +1368,7 @@ class Clinic(Analysis):
|
|
|
1355
1368
|
ssailification = self.project.analyses.Ssailification(
|
|
1356
1369
|
self.function,
|
|
1357
1370
|
ail_graph,
|
|
1371
|
+
fail_fast=self._fail_fast,
|
|
1358
1372
|
entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
|
|
1359
1373
|
ail_manager=self._ail_manager,
|
|
1360
1374
|
ssa_tmps=True,
|
|
@@ -1369,6 +1383,7 @@ class Clinic(Analysis):
|
|
|
1369
1383
|
dephication = self.project.analyses.GraphDephicationVVarMapping(
|
|
1370
1384
|
self.function,
|
|
1371
1385
|
ail_graph,
|
|
1386
|
+
fail_fast=self._fail_fast,
|
|
1372
1387
|
entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
|
|
1373
1388
|
vvar_id_start=self.vvar_id_start,
|
|
1374
1389
|
)
|
|
@@ -1421,6 +1436,7 @@ class Clinic(Analysis):
|
|
|
1421
1436
|
rd = self.project.analyses.SReachingDefinitions(
|
|
1422
1437
|
subject=self.function,
|
|
1423
1438
|
func_graph=ail_graph,
|
|
1439
|
+
fail_fast=self._fail_fast,
|
|
1424
1440
|
# use_callee_saved_regs_at_return=not self._register_save_areas_removed, FIXME
|
|
1425
1441
|
)
|
|
1426
1442
|
|
|
@@ -1431,6 +1447,7 @@ class Clinic(Analysis):
|
|
|
1431
1447
|
def _handler(block):
|
|
1432
1448
|
csm = self.project.analyses.AILCallSiteMaker(
|
|
1433
1449
|
block,
|
|
1450
|
+
fail_fast=self._fail_fast,
|
|
1434
1451
|
reaching_definitions=rd,
|
|
1435
1452
|
stack_pointer_tracker=stack_pointer_tracker,
|
|
1436
1453
|
ail_manager=self._ail_manager,
|
|
@@ -1444,6 +1461,7 @@ class Clinic(Analysis):
|
|
|
1444
1461
|
simp = self.project.analyses.AILBlockSimplifier(
|
|
1445
1462
|
ail_block,
|
|
1446
1463
|
self.function.addr,
|
|
1464
|
+
fail_fast=self._fail_fast,
|
|
1447
1465
|
stack_pointer_tracker=stack_pointer_tracker,
|
|
1448
1466
|
peephole_optimizations=self.peephole_optimizations,
|
|
1449
1467
|
)
|
|
@@ -1527,6 +1545,7 @@ class Clinic(Analysis):
|
|
|
1527
1545
|
tmp_kb.functions = self.kb.functions
|
|
1528
1546
|
vr = self.project.analyses.VariableRecoveryFast(
|
|
1529
1547
|
self.function, # pylint:disable=unused-variable
|
|
1548
|
+
fail_fast=self._fail_fast,
|
|
1530
1549
|
func_graph=ail_graph,
|
|
1531
1550
|
kb=tmp_kb,
|
|
1532
1551
|
track_sp=False,
|
|
@@ -1559,6 +1578,7 @@ class Clinic(Analysis):
|
|
|
1559
1578
|
vr.type_constraints,
|
|
1560
1579
|
vr.func_typevar,
|
|
1561
1580
|
kb=tmp_kb,
|
|
1581
|
+
fail_fast=self._fail_fast,
|
|
1562
1582
|
var_mapping=vr.var_to_typevars,
|
|
1563
1583
|
must_struct=must_struct,
|
|
1564
1584
|
ground_truth=groundtruth,
|
|
@@ -235,6 +235,7 @@ class Decompiler(Analysis):
|
|
|
235
235
|
clinic = self.project.analyses.Clinic(
|
|
236
236
|
self.func,
|
|
237
237
|
kb=self.kb,
|
|
238
|
+
fail_fast=self._fail_fast,
|
|
238
239
|
variable_kb=variable_kb,
|
|
239
240
|
reset_variable_names=reset_variable_names,
|
|
240
241
|
optimization_passes=self._optimization_passes,
|
|
@@ -248,6 +249,8 @@ class Decompiler(Analysis):
|
|
|
248
249
|
inline_functions=self._inline_functions,
|
|
249
250
|
desired_variables=self._desired_variables,
|
|
250
251
|
optimization_scratch=self._optimization_scratch,
|
|
252
|
+
force_loop_single_exit=self._force_loop_single_exit,
|
|
253
|
+
complete_successors=self._complete_successors,
|
|
251
254
|
**self.options_to_params(self.options_by_class["clinic"]),
|
|
252
255
|
)
|
|
253
256
|
else:
|
|
@@ -308,7 +311,7 @@ class Decompiler(Analysis):
|
|
|
308
311
|
self._update_progress(75.0, text="Structuring code")
|
|
309
312
|
|
|
310
313
|
# structure it
|
|
311
|
-
rs = self.project.analyses[RecursiveStructurer].prep(kb=self.kb)(
|
|
314
|
+
rs = self.project.analyses[RecursiveStructurer].prep(kb=self.kb, fail_fast=self._fail_fast)(
|
|
312
315
|
ri.region,
|
|
313
316
|
cond_proc=cond_proc,
|
|
314
317
|
func=self.func,
|
|
@@ -321,6 +324,7 @@ class Decompiler(Analysis):
|
|
|
321
324
|
self.func,
|
|
322
325
|
rs.result,
|
|
323
326
|
kb=self.kb,
|
|
327
|
+
fail_fast=self._fail_fast,
|
|
324
328
|
variable_kb=clinic.variable_kb,
|
|
325
329
|
**self.options_to_params(self.options_by_class["region_simplifier"]),
|
|
326
330
|
)
|
|
@@ -345,6 +349,7 @@ class Decompiler(Analysis):
|
|
|
345
349
|
flavor=self._flavor,
|
|
346
350
|
func_args=clinic.arg_list,
|
|
347
351
|
kb=self.kb,
|
|
352
|
+
fail_fast=self._fail_fast,
|
|
348
353
|
variable_kb=clinic.variable_kb,
|
|
349
354
|
expr_comments=old_codegen.expr_comments if old_codegen is not None else None,
|
|
350
355
|
stmt_comments=old_codegen.stmt_comments if old_codegen is not None else None,
|
|
@@ -365,7 +370,7 @@ class Decompiler(Analysis):
|
|
|
365
370
|
self.kb.decompilations[(self.func.addr, self._flavor)] = self.cache
|
|
366
371
|
|
|
367
372
|
def _recover_regions(self, graph: networkx.DiGraph, condition_processor, update_graph: bool = True):
|
|
368
|
-
return self.project.analyses[RegionIdentifier].prep(kb=self.kb)(
|
|
373
|
+
return self.project.analyses[RegionIdentifier].prep(kb=self.kb, fail_fast=self._fail_fast)(
|
|
369
374
|
self.func,
|
|
370
375
|
graph=graph,
|
|
371
376
|
cond_proc=condition_processor,
|
|
@@ -418,6 +423,8 @@ class Decompiler(Analysis):
|
|
|
418
423
|
reaching_definitions=reaching_definitions,
|
|
419
424
|
entry_node_addr=self.clinic.entry_node_addr,
|
|
420
425
|
scratch=self._optimization_scratch,
|
|
426
|
+
force_loop_single_exit=self._force_loop_single_exit,
|
|
427
|
+
complete_successors=self._complete_successors,
|
|
421
428
|
**kwargs,
|
|
422
429
|
)
|
|
423
430
|
|
|
@@ -478,6 +485,8 @@ class Decompiler(Analysis):
|
|
|
478
485
|
vvar_id_start=self.vvar_id_start,
|
|
479
486
|
entry_node_addr=self.clinic.entry_node_addr,
|
|
480
487
|
scratch=self._optimization_scratch,
|
|
488
|
+
force_loop_single_exit=self._force_loop_single_exit,
|
|
489
|
+
complete_successors=self._complete_successors,
|
|
481
490
|
**kwargs,
|
|
482
491
|
)
|
|
483
492
|
|
|
@@ -561,6 +570,7 @@ class Decompiler(Analysis):
|
|
|
561
570
|
type_constraints,
|
|
562
571
|
func_typevar,
|
|
563
572
|
kb=var_kb,
|
|
573
|
+
fail_fast=self._fail_fast,
|
|
564
574
|
var_mapping=var_to_typevar,
|
|
565
575
|
must_struct=must_struct,
|
|
566
576
|
ground_truth=groundtruth,
|
|
@@ -628,11 +638,15 @@ class Decompiler(Analysis):
|
|
|
628
638
|
)
|
|
629
639
|
|
|
630
640
|
def _transform_graph_from_ssa(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
|
|
631
|
-
dephication = self.project.analyses.GraphDephication(
|
|
641
|
+
dephication = self.project.analyses.GraphDephication(
|
|
642
|
+
self.func, ail_graph, rewrite=True, kb=self.kb, fail_fast=self._fail_fast
|
|
643
|
+
)
|
|
632
644
|
return dephication.output
|
|
633
645
|
|
|
634
646
|
def _transform_seqnode_from_ssa(self, seq_node: SequenceNode) -> SequenceNode:
|
|
635
|
-
dephication = self.project.analyses.SeqNodeDephication(
|
|
647
|
+
dephication = self.project.analyses.SeqNodeDephication(
|
|
648
|
+
self.func, seq_node, rewrite=True, kb=self.kb, fail_fast=self._fail_fast
|
|
649
|
+
)
|
|
636
650
|
return dephication.output
|
|
637
651
|
|
|
638
652
|
@staticmethod
|
|
@@ -382,12 +382,9 @@ class GraphRegion:
|
|
|
382
382
|
if src in graph:
|
|
383
383
|
graph.add_edge(src, dst)
|
|
384
384
|
else:
|
|
385
|
-
# it may happen that the dst node
|
|
386
|
-
#
|
|
387
|
-
|
|
388
|
-
for src in sub_graph.nodes:
|
|
389
|
-
if sub_graph.out_degree[src] == 0:
|
|
390
|
-
graph.add_edge(src, dst)
|
|
385
|
+
# it may happen that the dst node no longer exists in sub_graph or its successors
|
|
386
|
+
# this is because we have deemed that the dst node is no longer a valid successor for sub_graph
|
|
387
|
+
pass
|
|
391
388
|
|
|
392
389
|
graph.add_nodes_from(sub_graph_nodes)
|
|
393
390
|
graph.add_edges_from(sub_graph_edges)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# pylint:disable=unused-argument
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
|
|
5
|
+
import ailment
|
|
6
|
+
|
|
7
|
+
from .sequence_walker import SequenceWalker
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LabelCollector:
|
|
11
|
+
"""
|
|
12
|
+
Collect all labels.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, node):
|
|
16
|
+
self.root = node
|
|
17
|
+
self.labels: defaultdict[str, list[tuple[int, int | None]]] = defaultdict(list)
|
|
18
|
+
|
|
19
|
+
handlers = {
|
|
20
|
+
ailment.Block: self._handle_Block,
|
|
21
|
+
}
|
|
22
|
+
self._walker = SequenceWalker(handlers=handlers)
|
|
23
|
+
self._walker.walk(self.root)
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# Handlers
|
|
27
|
+
#
|
|
28
|
+
|
|
29
|
+
def _handle_Block(self, block: ailment.Block, **kwargs):
|
|
30
|
+
for stmt in block.statements:
|
|
31
|
+
if isinstance(stmt, ailment.Stmt.Label):
|
|
32
|
+
self.labels[stmt.name].append((block.addr, block.idx))
|
|
@@ -32,6 +32,7 @@ from .inlined_string_transformation_simplifier import InlinedStringTransformatio
|
|
|
32
32
|
from .const_prop_reverter import ConstPropOptReverter
|
|
33
33
|
from .call_stmt_rewriter import CallStatementRewriter
|
|
34
34
|
from .duplication_reverter import DuplicationReverter
|
|
35
|
+
from .switch_reused_entry_rewriter import SwitchReusedEntryRewriter
|
|
35
36
|
|
|
36
37
|
if TYPE_CHECKING:
|
|
37
38
|
from angr.analyses.decompiler.presets import DecompilationPreset
|
|
@@ -55,6 +56,7 @@ ALL_OPTIMIZATION_PASSES = [
|
|
|
55
56
|
ReturnDuplicatorHigh,
|
|
56
57
|
DeadblockRemover,
|
|
57
58
|
SwitchDefaultCaseDuplicator,
|
|
59
|
+
SwitchReusedEntryRewriter,
|
|
58
60
|
ConstPropOptReverter,
|
|
59
61
|
DuplicationReverter,
|
|
60
62
|
LoweredSwitchSimplifier,
|
|
@@ -129,6 +131,7 @@ __all__ = (
|
|
|
129
131
|
"CrossJumpReverter",
|
|
130
132
|
"CodeMotionOptimization",
|
|
131
133
|
"SwitchDefaultCaseDuplicator",
|
|
134
|
+
"SwitchReusedEntryRewriter",
|
|
132
135
|
"DeadblockRemover",
|
|
133
136
|
"InlinedStringTransformationSimplifier",
|
|
134
137
|
"ConstPropOptReverter",
|
|
@@ -118,6 +118,8 @@ class OptimizationPass(BaseOptimizationPass):
|
|
|
118
118
|
vvar_id_start=None,
|
|
119
119
|
entry_node_addr=None,
|
|
120
120
|
scratch: dict[str, Any] | None = None,
|
|
121
|
+
force_loop_single_exit: bool = True,
|
|
122
|
+
complete_successors: bool = False,
|
|
121
123
|
**kwargs,
|
|
122
124
|
):
|
|
123
125
|
super().__init__(func)
|
|
@@ -134,6 +136,8 @@ class OptimizationPass(BaseOptimizationPass):
|
|
|
134
136
|
self.entry_node_addr: tuple[int, int | None] = (
|
|
135
137
|
entry_node_addr if entry_node_addr is not None else (func.addr, None)
|
|
136
138
|
)
|
|
139
|
+
self._force_loop_single_exit = force_loop_single_exit
|
|
140
|
+
self._complete_successors = complete_successors
|
|
137
141
|
|
|
138
142
|
# output
|
|
139
143
|
self.out_graph: networkx.DiGraph | None = None
|
|
@@ -255,9 +259,8 @@ class OptimizationPass(BaseOptimizationPass):
|
|
|
255
259
|
graph=graph,
|
|
256
260
|
cond_proc=condition_processor or ConditionProcessor(self.project.arch),
|
|
257
261
|
update_graph=update_graph,
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
complete_successors=False,
|
|
262
|
+
force_loop_single_exit=self._force_loop_single_exit,
|
|
263
|
+
complete_successors=self._complete_successors,
|
|
261
264
|
entry_node_addr=self.entry_node_addr,
|
|
262
265
|
)
|
|
263
266
|
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# pylint:disable=too-many-boolean-expressions
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
from itertools import count
|
|
4
|
+
from collections import defaultdict
|
|
4
5
|
import logging
|
|
5
6
|
|
|
6
7
|
import networkx
|
|
7
8
|
|
|
9
|
+
from ailment.block import Block
|
|
10
|
+
from ailment.statement import Jump
|
|
11
|
+
from ailment.expression import Const
|
|
12
|
+
|
|
8
13
|
from angr.knowledge_plugins.cfg import IndirectJumpType
|
|
9
14
|
from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
10
15
|
|
|
@@ -29,17 +34,19 @@ class SwitchDefaultCaseDuplicator(OptimizationPass):
|
|
|
29
34
|
|
|
30
35
|
ARCHES = None
|
|
31
36
|
PLATFORMS = None
|
|
32
|
-
STAGE = OptimizationPassStage.
|
|
37
|
+
STAGE = OptimizationPassStage.AFTER_AIL_GRAPH_CREATION
|
|
33
38
|
NAME = "Duplicate default-case nodes to undo default-case node reuse caused by compiler code deduplication"
|
|
34
39
|
DESCRIPTION = __doc__.strip()
|
|
35
40
|
|
|
36
41
|
def __init__(self, func, **kwargs):
|
|
37
42
|
super().__init__(func, **kwargs)
|
|
38
43
|
|
|
39
|
-
self.node_idx = count(start=0)
|
|
44
|
+
self.node_idx = count(start=self._scratch.get("node_idx", 0))
|
|
40
45
|
|
|
41
46
|
self.analyze()
|
|
42
47
|
|
|
48
|
+
self._scratch["node_idx"] = next(self.node_idx)
|
|
49
|
+
|
|
43
50
|
def _check(self):
|
|
44
51
|
jumptables = self.kb.cfgs.get_most_accurate().jump_tables
|
|
45
52
|
switch_jump_block_addrs = {
|
|
@@ -77,8 +84,39 @@ class SwitchDefaultCaseDuplicator(OptimizationPass):
|
|
|
77
84
|
out_graph = None
|
|
78
85
|
duplicated_default_addrs: set[int] = set()
|
|
79
86
|
|
|
87
|
+
default_addr_count = defaultdict(int)
|
|
88
|
+
goto_rewritten_default_addrs = set()
|
|
89
|
+
for _, _, default_addr in default_case_node_addrs:
|
|
90
|
+
default_addr_count[default_addr] += 1
|
|
91
|
+
for default_addr, cnt in default_addr_count.items():
|
|
92
|
+
if cnt > 1:
|
|
93
|
+
# rewrite all of them into gotos
|
|
94
|
+
default_node = self._get_block(default_addr)
|
|
95
|
+
for switch_head_addr in sorted((sa for sa, _, da in default_case_node_addrs if da == default_addr)):
|
|
96
|
+
switch_head_node = self._get_block(switch_head_addr)
|
|
97
|
+
goto_stmt = Jump(
|
|
98
|
+
None,
|
|
99
|
+
Const(None, None, default_addr, self.project.arch.bits, ins_addr=default_addr),
|
|
100
|
+
target_idx=None, # I'm assuming the ID of the default node is None here
|
|
101
|
+
ins_addr=default_addr,
|
|
102
|
+
)
|
|
103
|
+
goto_node = Block(
|
|
104
|
+
default_addr,
|
|
105
|
+
0,
|
|
106
|
+
statements=[goto_stmt],
|
|
107
|
+
idx=next(self.node_idx),
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
if out_graph is None:
|
|
111
|
+
out_graph = self._graph
|
|
112
|
+
out_graph.remove_edge(switch_head_node, default_node)
|
|
113
|
+
out_graph.add_edge(switch_head_node, goto_node)
|
|
114
|
+
out_graph.add_edge(goto_node, default_node)
|
|
115
|
+
|
|
116
|
+
goto_rewritten_default_addrs.add(default_addr)
|
|
117
|
+
|
|
80
118
|
for switch_head_addr, jump_node_addr, default_addr in default_case_node_addrs:
|
|
81
|
-
if default_addr in duplicated_default_addrs:
|
|
119
|
+
if default_addr in duplicated_default_addrs or default_addr in goto_rewritten_default_addrs:
|
|
82
120
|
continue
|
|
83
121
|
|
|
84
122
|
default_case_node = self._func.get_node(default_addr)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# pylint:disable=too-many-boolean-expressions
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from itertools import count
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
from ailment.block import Block
|
|
7
|
+
from ailment.statement import Jump
|
|
8
|
+
from ailment.expression import Const
|
|
9
|
+
|
|
10
|
+
from angr.knowledge_plugins.cfg import IndirectJumpType
|
|
11
|
+
|
|
12
|
+
from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
_l = logging.getLogger(name=__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SwitchReusedEntryRewriter(OptimizationPass):
|
|
19
|
+
"""
|
|
20
|
+
For each switch-case construct (identified by jump tables), rewrite the entry into a goto block when we detect
|
|
21
|
+
situations where an entry node is reused by edges in switch-case constructs that are not the current one. This code
|
|
22
|
+
reuse is usually caused by compiler code deduplication.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
ARCHES = None
|
|
26
|
+
PLATFORMS = None
|
|
27
|
+
STAGE = OptimizationPassStage.AFTER_AIL_GRAPH_CREATION
|
|
28
|
+
NAME = "Rewrite switch-case entry nodes with multiple predecessors into goto statements."
|
|
29
|
+
DESCRIPTION = __doc__.strip()
|
|
30
|
+
|
|
31
|
+
def __init__(self, func, **kwargs):
|
|
32
|
+
super().__init__(func, **kwargs)
|
|
33
|
+
|
|
34
|
+
self.node_idx = count(start=self._scratch.get("node_idx", 0))
|
|
35
|
+
|
|
36
|
+
self.analyze()
|
|
37
|
+
|
|
38
|
+
self._scratch["node_idx"] = next(self.node_idx)
|
|
39
|
+
|
|
40
|
+
def _check(self):
|
|
41
|
+
jumptables = self.kb.cfgs.get_most_accurate().jump_tables
|
|
42
|
+
switch_jump_block_addrs = {
|
|
43
|
+
jumptable.addr
|
|
44
|
+
for jumptable in jumptables.values()
|
|
45
|
+
if jumptable.type
|
|
46
|
+
in {IndirectJumpType.Jumptable_AddressComputed, IndirectJumpType.Jumptable_AddressLoadedFromMemory}
|
|
47
|
+
}
|
|
48
|
+
jump_node_addrs = self._func.block_addrs_set.intersection(switch_jump_block_addrs)
|
|
49
|
+
if not jump_node_addrs:
|
|
50
|
+
return False, None
|
|
51
|
+
|
|
52
|
+
# ensure each jump table entry node has only one predecessor
|
|
53
|
+
reused_entries: dict[Block, set[Block]] = {}
|
|
54
|
+
for jumptable in jumptables.values():
|
|
55
|
+
for entry_addr in sorted(set(jumptable.jumptable_entries)):
|
|
56
|
+
entry_nodes = self._get_blocks(entry_addr)
|
|
57
|
+
for entry_node in entry_nodes:
|
|
58
|
+
preds = list(self._graph.predecessors(entry_node))
|
|
59
|
+
if len(preds) > 1:
|
|
60
|
+
non_current_jumptable_preds = [pred for pred in preds if pred.addr != jumptable.addr]
|
|
61
|
+
if any(p.addr in switch_jump_block_addrs for p in non_current_jumptable_preds):
|
|
62
|
+
reused_entries[entry_node] = {
|
|
63
|
+
pred for pred in preds if pred.addr in switch_jump_block_addrs
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if not reused_entries:
|
|
67
|
+
return False, None
|
|
68
|
+
cache = {"reused_entries": reused_entries}
|
|
69
|
+
return True, cache
|
|
70
|
+
|
|
71
|
+
def _analyze(self, cache=None):
|
|
72
|
+
|
|
73
|
+
reused_entries: dict[Block, set[Block]] = cache["reused_entries"]
|
|
74
|
+
out_graph = None
|
|
75
|
+
|
|
76
|
+
for entry_node, pred_nodes in reused_entries.items():
|
|
77
|
+
# we assign the entry node to the predecessor with the lowest address
|
|
78
|
+
sorted_pred_nodes = sorted(pred_nodes, key=lambda x: (x.addr, x.idx))
|
|
79
|
+
|
|
80
|
+
for head_node in sorted_pred_nodes[1:]:
|
|
81
|
+
|
|
82
|
+
# create the new goto node
|
|
83
|
+
goto_stmt = Jump(
|
|
84
|
+
None,
|
|
85
|
+
Const(None, None, entry_node.addr, self.project.arch.bits, ins_addr=entry_node.addr),
|
|
86
|
+
target_idx=entry_node.idx,
|
|
87
|
+
ins_addr=entry_node.addr,
|
|
88
|
+
)
|
|
89
|
+
goto_node = Block(
|
|
90
|
+
entry_node.addr,
|
|
91
|
+
0,
|
|
92
|
+
statements=[goto_stmt],
|
|
93
|
+
idx=next(self.node_idx),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if out_graph is None:
|
|
97
|
+
out_graph = self._graph
|
|
98
|
+
out_graph.remove_edge(head_node, entry_node)
|
|
99
|
+
out_graph.add_edge(head_node, goto_node)
|
|
100
|
+
# we are virtualizing these edges, so we don't need to add the edge from goto_node to the entry_node
|
|
101
|
+
|
|
102
|
+
self.out_graph = out_graph
|
|
@@ -9,6 +9,7 @@ from angr.analyses.decompiler.optimization_passes import (
|
|
|
9
9
|
RetAddrSaveSimplifier,
|
|
10
10
|
X86GccGetPcSimplifier,
|
|
11
11
|
CallStatementRewriter,
|
|
12
|
+
SwitchReusedEntryRewriter,
|
|
12
13
|
)
|
|
13
14
|
|
|
14
15
|
|
|
@@ -23,6 +24,7 @@ preset_basic = DecompilationPreset(
|
|
|
23
24
|
RetAddrSaveSimplifier,
|
|
24
25
|
X86GccGetPcSimplifier,
|
|
25
26
|
CallStatementRewriter,
|
|
27
|
+
SwitchReusedEntryRewriter,
|
|
26
28
|
],
|
|
27
29
|
)
|
|
28
30
|
|
|
@@ -21,6 +21,7 @@ from angr.analyses.decompiler.optimization_passes import (
|
|
|
21
21
|
CallStatementRewriter,
|
|
22
22
|
MultiSimplifier,
|
|
23
23
|
DeadblockRemover,
|
|
24
|
+
SwitchReusedEntryRewriter,
|
|
24
25
|
)
|
|
25
26
|
|
|
26
27
|
|
|
@@ -41,6 +42,7 @@ preset_fast = DecompilationPreset(
|
|
|
41
42
|
ReturnDuplicatorHigh,
|
|
42
43
|
DeadblockRemover,
|
|
43
44
|
SwitchDefaultCaseDuplicator,
|
|
45
|
+
SwitchReusedEntryRewriter,
|
|
44
46
|
LoweredSwitchSimplifier,
|
|
45
47
|
ReturnDuplicatorLow,
|
|
46
48
|
ReturnDeduplicator,
|
|
@@ -26,6 +26,7 @@ from angr.analyses.decompiler.optimization_passes import (
|
|
|
26
26
|
FlipBooleanCmp,
|
|
27
27
|
InlinedStringTransformationSimplifier,
|
|
28
28
|
CallStatementRewriter,
|
|
29
|
+
SwitchReusedEntryRewriter,
|
|
29
30
|
)
|
|
30
31
|
|
|
31
32
|
|
|
@@ -57,6 +58,7 @@ preset_full = DecompilationPreset(
|
|
|
57
58
|
FlipBooleanCmp,
|
|
58
59
|
InlinedStringTransformationSimplifier,
|
|
59
60
|
CallStatementRewriter,
|
|
61
|
+
SwitchReusedEntryRewriter,
|
|
60
62
|
],
|
|
61
63
|
)
|
|
62
64
|
|
|
@@ -532,7 +532,7 @@ class RegionIdentifier(Analysis):
|
|
|
532
532
|
)
|
|
533
533
|
if len(region.successors) > 1 and self._force_loop_single_exit:
|
|
534
534
|
# multi-successor region. refinement is required
|
|
535
|
-
self.
|
|
535
|
+
self._refine_loop_successors_to_guarded_successors(region, graph)
|
|
536
536
|
|
|
537
537
|
# if the head node is in the graph and it's not the head of the graph, we will need to update the head node
|
|
538
538
|
# address.
|
|
@@ -543,10 +543,10 @@ class RegionIdentifier(Analysis):
|
|
|
543
543
|
|
|
544
544
|
return region
|
|
545
545
|
|
|
546
|
-
def
|
|
546
|
+
def _refine_loop_successors_to_guarded_successors(self, region, graph: networkx.DiGraph):
|
|
547
547
|
"""
|
|
548
|
-
If there are multiple successors of a loop, convert them into
|
|
549
|
-
only one loop successor.
|
|
548
|
+
If there are multiple successors of a loop, convert them into guarded successors. Eventually there should be
|
|
549
|
+
only one loop successor. This is used in the DREAM structuring algorithm.
|
|
550
550
|
|
|
551
551
|
:param GraphRegion region: The cyclic region to refine.
|
|
552
552
|
:param networkx.DiGraph graph: The current graph that is being structured.
|
|
@@ -565,11 +565,11 @@ class RegionIdentifier(Analysis):
|
|
|
565
565
|
cond = ConditionNode(
|
|
566
566
|
condnode_addr,
|
|
567
567
|
None,
|
|
568
|
-
self.cond_proc.reaching_conditions[successors[
|
|
569
|
-
successors[
|
|
570
|
-
false_node=
|
|
568
|
+
self.cond_proc.reaching_conditions[successors[1]],
|
|
569
|
+
successors[1],
|
|
570
|
+
false_node=successors[0],
|
|
571
571
|
)
|
|
572
|
-
for succ in successors[
|
|
572
|
+
for succ in successors[2:]:
|
|
573
573
|
cond = ConditionNode(
|
|
574
574
|
condnode_addr,
|
|
575
575
|
None,
|
|
@@ -127,6 +127,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
127
127
|
@staticmethod
|
|
128
128
|
def _assert_graph_ok(g, msg: str) -> None:
|
|
129
129
|
if _DEBUG:
|
|
130
|
+
if g is None:
|
|
131
|
+
return
|
|
130
132
|
assert (
|
|
131
133
|
len(list(networkx.connected_components(networkx.Graph(g)))) <= 1
|
|
132
134
|
), f"{msg}: More than one connected component. Please report this."
|
|
@@ -229,7 +231,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
229
231
|
)
|
|
230
232
|
l.debug("... matching cyclic schemas: %s at %r", matched, node)
|
|
231
233
|
any_matches |= matched
|
|
232
|
-
|
|
234
|
+
if matched:
|
|
235
|
+
self._assert_graph_ok(self._region.graph, "Removed incorrect edges")
|
|
233
236
|
return any_matches
|
|
234
237
|
|
|
235
238
|
def _match_cyclic_schemas(self, node, head, graph, full_graph) -> bool:
|
|
@@ -559,9 +562,12 @@ class PhoenixStructurer(StructurerBase):
|
|
|
559
562
|
seq_node = SequenceNode(node.addr, nodes=[node])
|
|
560
563
|
seen_nodes = set()
|
|
561
564
|
while True:
|
|
562
|
-
succs = list(
|
|
565
|
+
succs = list(graph.successors(next_node))
|
|
563
566
|
if len(succs) != 1:
|
|
564
567
|
return False, None
|
|
568
|
+
if full_graph.out_degree[next_node] > 1:
|
|
569
|
+
# all successors in the full graph should have been refined away at this point
|
|
570
|
+
return False, None
|
|
565
571
|
next_node = succs[0]
|
|
566
572
|
|
|
567
573
|
if next_node is node:
|
|
@@ -600,6 +606,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
600
606
|
refined = self._refine_cyclic_core(head)
|
|
601
607
|
l.debug("... refined: %s", refined)
|
|
602
608
|
if refined:
|
|
609
|
+
self._assert_graph_ok(self._region.graph, "Refinement went wrong")
|
|
610
|
+
# cyclic refinement may create dangling nodes in the full graph
|
|
603
611
|
return True
|
|
604
612
|
return False
|
|
605
613
|
|
|
@@ -1020,7 +1028,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1020
1028
|
any_matches |= matched
|
|
1021
1029
|
if matched:
|
|
1022
1030
|
break
|
|
1023
|
-
|
|
1031
|
+
|
|
1032
|
+
self._assert_graph_ok(self._region.graph, "Removed incorrect edges")
|
|
1033
|
+
|
|
1024
1034
|
return any_matches
|
|
1025
1035
|
|
|
1026
1036
|
# switch cases
|
|
@@ -1094,7 +1104,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1094
1104
|
to_remove,
|
|
1095
1105
|
graph,
|
|
1096
1106
|
full_graph,
|
|
1097
|
-
|
|
1107
|
+
bail_on_nonhead_outedges=True,
|
|
1098
1108
|
)
|
|
1099
1109
|
if not r:
|
|
1100
1110
|
return False
|
|
@@ -1161,18 +1171,18 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1161
1171
|
node_pred = next(iter(graph.predecessors(node)))
|
|
1162
1172
|
|
|
1163
1173
|
case_nodes = list(graph.successors(node_a))
|
|
1164
|
-
case_node_successors = set()
|
|
1165
|
-
for case_node in case_nodes:
|
|
1166
|
-
if case_node is node_pred:
|
|
1167
|
-
continue
|
|
1168
|
-
if case_node.addr in jump_table.jumptable_entries:
|
|
1169
|
-
succs = set(graph.successors(case_node))
|
|
1170
|
-
case_node_successors |= {succ for succ in succs if succ.addr not in jump_table.jumptable_entries}
|
|
1171
|
-
if len(case_node_successors) > 1:
|
|
1172
|
-
return False
|
|
1173
1174
|
|
|
1174
|
-
#
|
|
1175
|
-
|
|
1175
|
+
# case 1: the common successor happens to be directly reachable from node_a (usually as a result of compiler
|
|
1176
|
+
# optimization)
|
|
1177
|
+
# example: touch_touch_no_switch.o:main
|
|
1178
|
+
r = self.switch_case_entry_node_has_common_successor_case_1(graph, jump_table, case_nodes, node_pred)
|
|
1179
|
+
|
|
1180
|
+
# case 2: the common successor is not directly reachable from node_a. this is a more common case.
|
|
1181
|
+
if not r:
|
|
1182
|
+
r |= self.switch_case_entry_node_has_common_successor_case_2(graph, jump_table, case_nodes, node_pred)
|
|
1183
|
+
|
|
1184
|
+
if not r:
|
|
1185
|
+
return False
|
|
1176
1186
|
|
|
1177
1187
|
# un-structure IncompleteSwitchCaseNode
|
|
1178
1188
|
if isinstance(node_a, SequenceNode) and node_a.nodes and isinstance(node_a.nodes[0], IncompleteSwitchCaseNode):
|
|
@@ -1186,8 +1196,10 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1186
1196
|
# update node_a
|
|
1187
1197
|
node_a = next(iter(nn for nn in graph.nodes if nn.addr == target))
|
|
1188
1198
|
|
|
1199
|
+
case_and_entry_addrs = self._find_case_and_entry_addrs(node_a, graph, cmp_lb, jump_table)
|
|
1200
|
+
|
|
1189
1201
|
cases, node_default, to_remove = self._switch_build_cases(
|
|
1190
|
-
|
|
1202
|
+
case_and_entry_addrs,
|
|
1191
1203
|
node,
|
|
1192
1204
|
node_a,
|
|
1193
1205
|
node_b_addr,
|
|
@@ -1203,7 +1215,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1203
1215
|
to_remove.add(node_default)
|
|
1204
1216
|
|
|
1205
1217
|
to_remove.add(node_a) # add node_a
|
|
1206
|
-
self._make_switch_cases_core(
|
|
1218
|
+
r = self._make_switch_cases_core(
|
|
1207
1219
|
node,
|
|
1208
1220
|
cmp_expr,
|
|
1209
1221
|
cases,
|
|
@@ -1215,7 +1227,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1215
1227
|
full_graph,
|
|
1216
1228
|
node_a=node_a,
|
|
1217
1229
|
)
|
|
1230
|
+
if not r:
|
|
1231
|
+
return False
|
|
1218
1232
|
|
|
1233
|
+
# fully structured into a switch-case. remove node from switch_case_known_heads
|
|
1234
|
+
self.switch_case_known_heads.remove(node)
|
|
1219
1235
|
self._switch_handle_gotos(cases, node_default, switch_end_addr)
|
|
1220
1236
|
|
|
1221
1237
|
return True
|
|
@@ -1253,8 +1269,10 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1253
1269
|
else:
|
|
1254
1270
|
return False
|
|
1255
1271
|
|
|
1272
|
+
case_and_entry_addrs = self._find_case_and_entry_addrs(node, graph, cmp_lb, jump_table)
|
|
1273
|
+
|
|
1256
1274
|
cases, node_default, to_remove = self._switch_build_cases(
|
|
1257
|
-
|
|
1275
|
+
case_and_entry_addrs,
|
|
1258
1276
|
node,
|
|
1259
1277
|
node,
|
|
1260
1278
|
default_addr,
|
|
@@ -1265,12 +1283,10 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1265
1283
|
# there must be a default case
|
|
1266
1284
|
return False
|
|
1267
1285
|
|
|
1268
|
-
self._make_switch_cases_core(
|
|
1286
|
+
return self._make_switch_cases_core(
|
|
1269
1287
|
node, cmp_expr, cases, default_addr, node_default, node.addr, to_remove, graph, full_graph
|
|
1270
1288
|
)
|
|
1271
1289
|
|
|
1272
|
-
return True
|
|
1273
|
-
|
|
1274
1290
|
def _match_acyclic_incomplete_switch_cases(
|
|
1275
1291
|
self, node, graph: networkx.DiGraph, full_graph: networkx.DiGraph, jump_tables: dict
|
|
1276
1292
|
) -> bool:
|
|
@@ -1322,14 +1338,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1322
1338
|
# and a case node (addr.b). The addr.a node is a successor to the head node while the addr.b node is a
|
|
1323
1339
|
# successor to node_a
|
|
1324
1340
|
default_node_candidates = [nn for nn in graph.nodes if nn.addr == node_b_addr]
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
node_default: BaseNode | None = default_node_candidates[0]
|
|
1329
|
-
else:
|
|
1330
|
-
node_default: BaseNode | None = next(
|
|
1331
|
-
iter(nn for nn in default_node_candidates if graph.has_edge(head_node, nn)), None
|
|
1332
|
-
)
|
|
1341
|
+
node_default: BaseNode | None = next(
|
|
1342
|
+
iter(nn for nn in default_node_candidates if graph.has_edge(head_node, nn)), None
|
|
1343
|
+
)
|
|
1333
1344
|
|
|
1334
1345
|
if node_default is not None and not isinstance(node_default, SequenceNode):
|
|
1335
1346
|
# make the default node a SequenceNode so that we can insert Break and Continue nodes into it later
|
|
@@ -1432,7 +1443,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1432
1443
|
graph: networkx.DiGraph,
|
|
1433
1444
|
full_graph: networkx.DiGraph,
|
|
1434
1445
|
node_a=None,
|
|
1435
|
-
|
|
1446
|
+
bail_on_nonhead_outedges: bool = False,
|
|
1436
1447
|
) -> bool:
|
|
1437
1448
|
scnode = SwitchCaseNode(cmp_expr, cases, node_default, addr=addr)
|
|
1438
1449
|
|
|
@@ -1454,14 +1465,24 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1454
1465
|
if dst not in to_remove:
|
|
1455
1466
|
out_edges.append((nn, dst))
|
|
1456
1467
|
|
|
1457
|
-
if
|
|
1468
|
+
if bail_on_nonhead_outedges:
|
|
1458
1469
|
nonhead_out_nodes = {edge[1] for edge in out_edges if edge[1] is not head}
|
|
1459
1470
|
if len(nonhead_out_nodes) > 1:
|
|
1460
1471
|
# not ready to be structured yet - do it later
|
|
1461
1472
|
return False
|
|
1462
1473
|
|
|
1474
|
+
# check if structuring will create any dangling nodes
|
|
1475
|
+
for case_node in to_remove:
|
|
1476
|
+
if case_node is not node_default and case_node is not node_a and case_node is not head:
|
|
1477
|
+
for succ in graph.successors(case_node):
|
|
1478
|
+
if succ is not case_node and succ is not head and graph.in_degree[succ] == 1:
|
|
1479
|
+
# succ will be dangling - not ready to be structured yet - do it later
|
|
1480
|
+
return False
|
|
1481
|
+
|
|
1463
1482
|
if node_default is not None:
|
|
1464
1483
|
# the head no longer goes to the default case
|
|
1484
|
+
if graph.has_edge(head, node_default):
|
|
1485
|
+
pass
|
|
1465
1486
|
graph.remove_edge(head, node_default)
|
|
1466
1487
|
full_graph.remove_edge(head, node_default)
|
|
1467
1488
|
else:
|
|
@@ -1505,6 +1526,13 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1505
1526
|
if full_graph.has_edge(head, out_dst):
|
|
1506
1527
|
full_graph.remove_edge(head, out_dst)
|
|
1507
1528
|
|
|
1529
|
+
# fix full_graph if needed: remove successors that are no longer needed
|
|
1530
|
+
for out_src, out_dst in out_edges[1:]:
|
|
1531
|
+
if out_dst in full_graph and out_dst not in graph and full_graph.in_degree[out_dst] == 0:
|
|
1532
|
+
full_graph.remove_node(out_dst)
|
|
1533
|
+
if out_dst in self._region.successors:
|
|
1534
|
+
self._region.successors.remove(out_dst)
|
|
1535
|
+
|
|
1508
1536
|
# remove the last statement (conditional jump) in the head node
|
|
1509
1537
|
remove_last_statement(head)
|
|
1510
1538
|
|
|
@@ -1514,6 +1542,25 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1514
1542
|
|
|
1515
1543
|
return True
|
|
1516
1544
|
|
|
1545
|
+
@staticmethod
|
|
1546
|
+
def _find_case_and_entry_addrs(
|
|
1547
|
+
jump_head, graph, cmp_lb: int, jump_table
|
|
1548
|
+
) -> dict[int, int | tuple[int, int | None]]:
|
|
1549
|
+
case_and_entry_addrs = {}
|
|
1550
|
+
|
|
1551
|
+
addr_to_entry_nodes = defaultdict(list)
|
|
1552
|
+
for succ in graph.successors(jump_head):
|
|
1553
|
+
addr_to_entry_nodes[succ.addr].append(succ)
|
|
1554
|
+
|
|
1555
|
+
for i, entry_addr in enumerate(jump_table.jumptable_entries):
|
|
1556
|
+
case_no = cmp_lb + i
|
|
1557
|
+
if entry_addr in addr_to_entry_nodes and isinstance(addr_to_entry_nodes[entry_addr][0], (MultiNode, Block)):
|
|
1558
|
+
case_and_entry_addrs[case_no] = entry_addr, addr_to_entry_nodes[entry_addr][0].idx
|
|
1559
|
+
else:
|
|
1560
|
+
case_and_entry_addrs[case_no] = entry_addr
|
|
1561
|
+
|
|
1562
|
+
return case_and_entry_addrs
|
|
1563
|
+
|
|
1517
1564
|
# other acyclic schemas
|
|
1518
1565
|
|
|
1519
1566
|
def _match_acyclic_sequence(self, graph, full_graph, start_node) -> bool:
|
|
@@ -1982,6 +2029,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1982
2029
|
|
|
1983
2030
|
if full_graph.in_degree[left] > 1 and full_graph.in_degree[right] == 1:
|
|
1984
2031
|
left, right = right, left
|
|
2032
|
+
|
|
2033
|
+
# ensure left and right nodes are not the head of a switch-case construct
|
|
2034
|
+
if left in self.switch_case_known_heads or right in self.switch_case_known_heads:
|
|
2035
|
+
return None
|
|
2036
|
+
|
|
1985
2037
|
if (
|
|
1986
2038
|
self._is_sequential_statement_block(left)
|
|
1987
2039
|
and full_graph.in_degree[left] == 1
|
|
@@ -2024,6 +2076,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2024
2076
|
|
|
2025
2077
|
if full_graph.in_degree[left] == 1 and full_graph.in_degree[right] == 2:
|
|
2026
2078
|
left, right = right, left
|
|
2079
|
+
|
|
2080
|
+
# ensure left and right nodes are not the head of a switch-case construct
|
|
2081
|
+
if left in self.switch_case_known_heads or right in self.switch_case_known_heads:
|
|
2082
|
+
return None
|
|
2083
|
+
|
|
2027
2084
|
if (
|
|
2028
2085
|
self._is_sequential_statement_block(right)
|
|
2029
2086
|
and full_graph.in_degree[left] == 2
|
|
@@ -2060,6 +2117,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2060
2117
|
|
|
2061
2118
|
if full_graph.in_degree[left] > 1 and full_graph.in_degree[successor] == 1:
|
|
2062
2119
|
left, successor = successor, left
|
|
2120
|
+
|
|
2121
|
+
# ensure left and successor nodes are not the head of a switch-case construct
|
|
2122
|
+
if left in self.switch_case_known_heads or successor in self.switch_case_known_heads:
|
|
2123
|
+
return None
|
|
2124
|
+
|
|
2063
2125
|
if (
|
|
2064
2126
|
self._is_sequential_statement_block(left)
|
|
2065
2127
|
and full_graph.in_degree[left] == 1
|
|
@@ -2103,6 +2165,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2103
2165
|
|
|
2104
2166
|
if full_graph.in_degree[left] > 1 and full_graph.in_degree[else_node] == 1:
|
|
2105
2167
|
left, else_node = else_node, left
|
|
2168
|
+
|
|
2169
|
+
# ensure left and else nodes are not the head of a switch-case construct
|
|
2170
|
+
if left in self.switch_case_known_heads or else_node in self.switch_case_known_heads:
|
|
2171
|
+
return None
|
|
2172
|
+
|
|
2106
2173
|
if (
|
|
2107
2174
|
self._is_sequential_statement_block(left)
|
|
2108
2175
|
and full_graph.in_degree[left] == 1
|
|
@@ -2563,3 +2630,36 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2563
2630
|
graph_with_str.add_edge(f'"{src!r}"', f'"{dst!r}"')
|
|
2564
2631
|
|
|
2565
2632
|
networkx.drawing.nx_pydot.write_dot(graph_with_str, path)
|
|
2633
|
+
|
|
2634
|
+
@staticmethod
|
|
2635
|
+
def switch_case_entry_node_has_common_successor_case_1(graph, jump_table, case_nodes, node_pred) -> bool:
|
|
2636
|
+
all_succs = set()
|
|
2637
|
+
for case_node in case_nodes:
|
|
2638
|
+
if case_node is node_pred:
|
|
2639
|
+
continue
|
|
2640
|
+
if case_node.addr in jump_table.jumptable_entries:
|
|
2641
|
+
all_succs |= set(graph.successors(case_node))
|
|
2642
|
+
|
|
2643
|
+
case_node_successors = set()
|
|
2644
|
+
for case_node in case_nodes:
|
|
2645
|
+
if case_node is node_pred:
|
|
2646
|
+
continue
|
|
2647
|
+
if case_node in all_succs:
|
|
2648
|
+
continue
|
|
2649
|
+
if case_node.addr in jump_table.jumptable_entries:
|
|
2650
|
+
succs = set(graph.successors(case_node))
|
|
2651
|
+
case_node_successors |= {succ for succ in succs if succ.addr not in jump_table.jumptable_entries}
|
|
2652
|
+
|
|
2653
|
+
return len(case_node_successors) <= 1
|
|
2654
|
+
|
|
2655
|
+
@staticmethod
|
|
2656
|
+
def switch_case_entry_node_has_common_successor_case_2(graph, jump_table, case_nodes, node_pred) -> bool:
|
|
2657
|
+
case_node_successors = set()
|
|
2658
|
+
for case_node in case_nodes:
|
|
2659
|
+
if case_node is node_pred:
|
|
2660
|
+
continue
|
|
2661
|
+
if case_node.addr in jump_table.jumptable_entries:
|
|
2662
|
+
succs = set(graph.successors(case_node))
|
|
2663
|
+
case_node_successors |= {succ for succ in succs if succ.addr not in jump_table.jumptable_entries}
|
|
2664
|
+
|
|
2665
|
+
return len(case_node_successors) <= 1
|
|
@@ -83,7 +83,9 @@ class RecursiveStructurer(Analysis):
|
|
|
83
83
|
# Get the parent region
|
|
84
84
|
parent_region = parent_map.get(current_region)
|
|
85
85
|
# structure this region
|
|
86
|
-
st: StructurerBase = self.project.analyses[self.structurer_cls].prep(
|
|
86
|
+
st: StructurerBase = self.project.analyses[self.structurer_cls].prep(
|
|
87
|
+
kb=self.kb, fail_fast=self._fail_fast
|
|
88
|
+
)(
|
|
87
89
|
current_region.copy(),
|
|
88
90
|
parent_map=parent_map,
|
|
89
91
|
condition_processor=self.cond_proc,
|
|
@@ -18,6 +18,7 @@ from angr.analyses.decompiler.utils import (
|
|
|
18
18
|
remove_last_statement,
|
|
19
19
|
has_nonlabel_nonphi_statements,
|
|
20
20
|
)
|
|
21
|
+
from angr.analyses.decompiler.label_collector import LabelCollector
|
|
21
22
|
from .structurer_nodes import (
|
|
22
23
|
MultiNode,
|
|
23
24
|
SequenceNode,
|
|
@@ -800,9 +801,17 @@ class StructurerBase(Analysis):
|
|
|
800
801
|
starting_case_ids.append(idx)
|
|
801
802
|
continue
|
|
802
803
|
|
|
804
|
+
# we can't just collect addresses and block IDs of switch-case entry nodes because SequenceNode does not keep
|
|
805
|
+
# track of block IDs.
|
|
806
|
+
case_label_addrs = set()
|
|
807
|
+
for case_node in cases.values():
|
|
808
|
+
lc = LabelCollector(case_node)
|
|
809
|
+
for lst in lc.labels.values():
|
|
810
|
+
case_label_addrs |= set(lst)
|
|
811
|
+
|
|
803
812
|
for idx in starting_case_ids:
|
|
804
813
|
new_cases[idx] = cases[idx]
|
|
805
|
-
self.
|
|
814
|
+
self._remove_last_statement_if_jump_to_addr(new_cases[idx], case_label_addrs)
|
|
806
815
|
succs = networkx.dfs_successors(graph, idx)
|
|
807
816
|
idx_ = idx
|
|
808
817
|
while idx_ in succs:
|
|
@@ -813,6 +822,29 @@ class StructurerBase(Analysis):
|
|
|
813
822
|
|
|
814
823
|
return new_cases
|
|
815
824
|
|
|
825
|
+
@staticmethod
|
|
826
|
+
def _remove_last_statement_if_jump_to_addr(
|
|
827
|
+
node: BaseNode | ailment.Block, addr_and_ids: set[tuple[int, int | None]]
|
|
828
|
+
) -> ailment.Stmt.Jump | ailment.Stmt.ConditionalJump | None:
|
|
829
|
+
try:
|
|
830
|
+
last_stmts = ConditionProcessor.get_last_statements(node)
|
|
831
|
+
except EmptyBlockNotice:
|
|
832
|
+
return None
|
|
833
|
+
|
|
834
|
+
if len(last_stmts) == 1 and isinstance(last_stmts[0], (ailment.Stmt.Jump, ailment.Stmt.ConditionalJump)):
|
|
835
|
+
last_stmt = last_stmts[0]
|
|
836
|
+
jump_targets = []
|
|
837
|
+
if isinstance(last_stmt, ailment.Stmt.Jump) and isinstance(last_stmt.target, ailment.Expr.Const):
|
|
838
|
+
jump_targets = [(last_stmt.target.value, last_stmt.target_idx)]
|
|
839
|
+
elif isinstance(last_stmt, ailment.Stmt.ConditionalJump):
|
|
840
|
+
if isinstance(last_stmt.true_target, ailment.Expr.Const):
|
|
841
|
+
jump_targets.append((last_stmt.true_target.value, last_stmt.true_target_idx))
|
|
842
|
+
if isinstance(last_stmt.false_target, ailment.Expr.Const):
|
|
843
|
+
jump_targets.append((last_stmt.false_target.value, last_stmt.false_target_idx))
|
|
844
|
+
if any(tpl in addr_and_ids for tpl in jump_targets):
|
|
845
|
+
return remove_last_statement(node)
|
|
846
|
+
return None
|
|
847
|
+
|
|
816
848
|
@staticmethod
|
|
817
849
|
def _remove_last_statement_if_jump(
|
|
818
850
|
node: BaseNode | ailment.Block,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: angr
|
|
3
|
-
Version: 9.2.
|
|
3
|
+
Version: 9.2.129
|
|
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
|
Home-page: https://github.com/angr/angr
|
|
6
6
|
License: BSD-2-Clause
|
|
@@ -16,13 +16,13 @@ Description-Content-Type: text/markdown
|
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: CppHeaderParser
|
|
18
18
|
Requires-Dist: GitPython
|
|
19
|
-
Requires-Dist: ailment==9.2.
|
|
20
|
-
Requires-Dist: archinfo==9.2.
|
|
19
|
+
Requires-Dist: ailment==9.2.129
|
|
20
|
+
Requires-Dist: archinfo==9.2.129
|
|
21
21
|
Requires-Dist: cachetools
|
|
22
22
|
Requires-Dist: capstone==5.0.3
|
|
23
23
|
Requires-Dist: cffi>=1.14.0
|
|
24
|
-
Requires-Dist: claripy==9.2.
|
|
25
|
-
Requires-Dist: cle==9.2.
|
|
24
|
+
Requires-Dist: claripy==9.2.129
|
|
25
|
+
Requires-Dist: cle==9.2.129
|
|
26
26
|
Requires-Dist: itanium-demangler
|
|
27
27
|
Requires-Dist: mulpyplexer
|
|
28
28
|
Requires-Dist: nampa
|
|
@@ -31,7 +31,7 @@ Requires-Dist: protobuf>=5.28.2
|
|
|
31
31
|
Requires-Dist: psutil
|
|
32
32
|
Requires-Dist: pycparser>=2.18
|
|
33
33
|
Requires-Dist: pyformlang
|
|
34
|
-
Requires-Dist: pyvex==9.2.
|
|
34
|
+
Requires-Dist: pyvex==9.2.129
|
|
35
35
|
Requires-Dist: rich>=13.1.0
|
|
36
36
|
Requires-Dist: sortedcontainers
|
|
37
37
|
Requires-Dist: sympy
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
angr/__init__.py,sha256=
|
|
1
|
+
angr/__init__.py,sha256=H7vjKb7cGcs7fXtPwftz3xSELPNZUzWL7xFWRC4tvvg,9153
|
|
2
2
|
angr/__main__.py,sha256=XeawhF6Cco9eWcfMTDWzYYggLB3qjnQ87IIeFOplaHM,2873
|
|
3
3
|
angr/annocfg.py,sha256=5fiS9TPt5r1_8g_qSfD2XkETlBdm5MTClBIQKqhm040,10624
|
|
4
4
|
angr/blade.py,sha256=GpbEumxMsb_6qD7TbtfZuW2CMzV7W1iwqYzQWYlXnxM,15394
|
|
@@ -102,19 +102,20 @@ angr/analyses/decompiler/block_io_finder.py,sha256=xMwG8Bi69OGNYVs0U0F4yxM8kEsny
|
|
|
102
102
|
angr/analyses/decompiler/block_similarity.py,sha256=ISMoOm-TGJ_1wD2i_4m8IYTletgnP66gReQESJnfvS0,6873
|
|
103
103
|
angr/analyses/decompiler/block_simplifier.py,sha256=_WYyfFW8bJ_-RkrudJIlDdHh9fc6_aHkuwzW9gylY-k,13922
|
|
104
104
|
angr/analyses/decompiler/callsite_maker.py,sha256=Gs_FmlmIs5jM-XccL9OMCaj_-L83NlYzkzxsy2HmcfQ,18749
|
|
105
|
-
angr/analyses/decompiler/clinic.py,sha256=
|
|
105
|
+
angr/analyses/decompiler/clinic.py,sha256=Psy7ljBDFOqYx_Al8xvDPe3naJi8YsdMryXo8wVlrhM,106999
|
|
106
106
|
angr/analyses/decompiler/condition_processor.py,sha256=MbpbSk6zXHmMLWjLAHxpYjcLCVL1TuL08KmTBTNpm_4,52839
|
|
107
107
|
angr/analyses/decompiler/decompilation_cache.py,sha256=ELz1DDVYvrs6IeUX4_L0OZDZICUifSBdJkdJXWrFZAY,1375
|
|
108
108
|
angr/analyses/decompiler/decompilation_options.py,sha256=QWUGnfQ0FUekGs_I6X-ZKvAvL39VX2hFRcZrlXd72fY,7957
|
|
109
|
-
angr/analyses/decompiler/decompiler.py,sha256=
|
|
109
|
+
angr/analyses/decompiler/decompiler.py,sha256=BF859tVg7IWwEnarW30dXoQYHXco3lngTh0vx7Q5Je8,28672
|
|
110
110
|
angr/analyses/decompiler/empty_node_remover.py,sha256=_RAGjqDyRmannEGPcMmWkL7em990-_sKgl5CYreb-yI,7403
|
|
111
111
|
angr/analyses/decompiler/expression_narrower.py,sha256=TvkqtgNI9aDsquqyNFH5kXLW04rP_J940GFhrGopxP4,10343
|
|
112
112
|
angr/analyses/decompiler/goto_manager.py,sha256=GUWt3Y_NCpmreIt4plxX5Y3UO2V8IVGZuRtF2GqI-cw,4006
|
|
113
|
-
angr/analyses/decompiler/graph_region.py,sha256=
|
|
113
|
+
angr/analyses/decompiler/graph_region.py,sha256=KFJ_8qCn0bbjPO1l0D2-eVqRzkgiLNpxiynhWHhtxdA,16538
|
|
114
114
|
angr/analyses/decompiler/jump_target_collector.py,sha256=qR11VsIp6H1N-19xCdXMRs1LGX31o3_Cz1Z5wRyMIl8,1173
|
|
115
115
|
angr/analyses/decompiler/jumptable_entry_condition_rewriter.py,sha256=f_JyNiSZfoudElfl2kIzONoYCiosR4xYFOe8Q5SkvLg,2176
|
|
116
|
+
angr/analyses/decompiler/label_collector.py,sha256=JLaGuSZu-DdJMBTYOPt4QpWJ6UigOpsC5bgNANrSao4,798
|
|
116
117
|
angr/analyses/decompiler/redundant_label_remover.py,sha256=J9hpP3C_P08v84FjVU0q5Rmj5M1N9q3HKWSWsA2u7Yg,5879
|
|
117
|
-
angr/analyses/decompiler/region_identifier.py,sha256=
|
|
118
|
+
angr/analyses/decompiler/region_identifier.py,sha256=DGxaIc3cy-NYxKeZgMO_BuybQvI86XXxNX88Ya6elAw,47396
|
|
118
119
|
angr/analyses/decompiler/region_walker.py,sha256=u0hR0bEX1hSwkv-vejIM1gS-hcX2F2DLsDqpKhQ5_pQ,752
|
|
119
120
|
angr/analyses/decompiler/return_maker.py,sha256=pKn9_y5VXqTeJnD5uzLLd9sH_Dp_9wkPcWPiJPTV-7A,2550
|
|
120
121
|
angr/analyses/decompiler/seq_to_blocks.py,sha256=bB-1m8oBO59AlAp6izAROks3BBxFW8zigLlrIMt6Yfs,564
|
|
@@ -135,7 +136,7 @@ angr/analyses/decompiler/dephication/graph_rewriting.py,sha256=R0rlwYL0Cnt1UPjdE
|
|
|
135
136
|
angr/analyses/decompiler/dephication/graph_vvar_mapping.py,sha256=nsMwppwMXrGC8_RF-neehpaz-7kmEORVhpAbjOdVFWM,13703
|
|
136
137
|
angr/analyses/decompiler/dephication/rewriting_engine.py,sha256=3KUIxwUmfTZj2Jm1mB98J5vMkHqy4LLPYTrLzZfLbBA,10442
|
|
137
138
|
angr/analyses/decompiler/dephication/seqnode_dephication.py,sha256=q29kS8lOs_-mxgJMtQvoZdw6l3q2lUDeXcTcGienIrY,4343
|
|
138
|
-
angr/analyses/decompiler/optimization_passes/__init__.py,sha256=
|
|
139
|
+
angr/analyses/decompiler/optimization_passes/__init__.py,sha256=7CvrHdbjvebdxzXYIvLqzKNv41bc19tecWZJBnEwEyo,4965
|
|
139
140
|
angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py,sha256=uUzQWVkeKL2C9Lq8NZ7UkkZBAXydxOd0F1jxr0Zi__Q,5514
|
|
140
141
|
angr/analyses/decompiler/optimization_passes/call_stmt_rewriter.py,sha256=G1CEWo62dAMrm-3V4DfEDxT6kwXxuks10bcTtW9C_tA,1320
|
|
141
142
|
angr/analyses/decompiler/optimization_passes/code_motion.py,sha256=7o6lf-qahXv5H8jLqEASVXHaz-_PGo3r6l7qH5PbDtU,15343
|
|
@@ -153,7 +154,7 @@ angr/analyses/decompiler/optimization_passes/ite_region_converter.py,sha256=zTpl
|
|
|
153
154
|
angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py,sha256=1Yto_EBmmB5FkwZzaAO7S0MEvbQNEknFbbq-nUU0Eao,38818
|
|
154
155
|
angr/analyses/decompiler/optimization_passes/mod_simplifier.py,sha256=papR480h-t_wEWMEdu6UTmc33lPSy_MOmiMgidPGnxc,3115
|
|
155
156
|
angr/analyses/decompiler/optimization_passes/multi_simplifier.py,sha256=sIp2YISvafpyFzn8sgGMfohJsARiS3JFX_Y3IUXD_vo,10119
|
|
156
|
-
angr/analyses/decompiler/optimization_passes/optimization_pass.py,sha256=
|
|
157
|
+
angr/analyses/decompiler/optimization_passes/optimization_pass.py,sha256=ZCGlsTK_3pF2uKdUkLoI2zkQTVvR3w1zt0ZLhy0_BcA,21530
|
|
157
158
|
angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py,sha256=tc4FruEl0sFpm1DUu9g8gWlueRm0t9rhfHsdUrVplBo,7932
|
|
158
159
|
angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py,sha256=GIFiYM_C_ChHrD2D1JGRFlE--PU3FOxTqzOX-lXmJLY,6404
|
|
159
160
|
angr/analyses/decompiler/optimization_passes/ret_deduplicator.py,sha256=STMnRyZWiqdoGPa3c7Q4KCHv-JHUdJ2t4oLEltEMpII,7995
|
|
@@ -161,7 +162,8 @@ angr/analyses/decompiler/optimization_passes/return_duplicator_base.py,sha256=7Q
|
|
|
161
162
|
angr/analyses/decompiler/optimization_passes/return_duplicator_high.py,sha256=ICDYwQJt5E2OVasdqn42jzbjwUXhSj6Plh3Y1iUHpAQ,2178
|
|
162
163
|
angr/analyses/decompiler/optimization_passes/return_duplicator_low.py,sha256=-mBEVfwGz986lDDEGwBG8wvGQTrFZHE7TLV-7rWt-H0,10076
|
|
163
164
|
angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py,sha256=cEbZ5jyYbRiBJSzVJbnqssUY5MzirXXgzvzpxllY_Zk,14343
|
|
164
|
-
angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py,sha256=
|
|
165
|
+
angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py,sha256=nMI9geZiLG5diaI3YciNKvJ0PAZXtUBLgAfknCf48QE,6539
|
|
166
|
+
angr/analyses/decompiler/optimization_passes/switch_reused_entry_rewriter.py,sha256=m7ZMkqE2qbl4rl4M_Fi8xS6I1vUaTzUBIzsE6qpbwkM,4020
|
|
165
167
|
angr/analyses/decompiler/optimization_passes/tag_slicer.py,sha256=8_gmoeYgDD1Hb8Rpqcb-01_B4897peDF-J6KA5PjQT8,1176
|
|
166
168
|
angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py,sha256=cpbsP6_ilZDu2M_jX8TEnwVrsQXljHEjSMw25HyK6PM,12806
|
|
167
169
|
angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py,sha256=6NxaX2oT6BMkevb8xt9vlS3Jl-CmSK59F0FVab68B48,3088
|
|
@@ -219,9 +221,9 @@ angr/analyses/decompiler/peephole_optimizations/single_bit_cond_to_boolexpr.py,s
|
|
|
219
221
|
angr/analyses/decompiler/peephole_optimizations/single_bit_xor.py,sha256=tnjWYeKWL63rvLVcicVSD1NbVQJfHtLT85E_PNeYt6s,979
|
|
220
222
|
angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py,sha256=RRzuc2iGzQPvYaZAmpLKim0pJ_yR3-muGnJQxvpcN8w,4786
|
|
221
223
|
angr/analyses/decompiler/presets/__init__.py,sha256=FfnTqgY3oINacW7JFPIxx3r9dwpgI0Pu8yygBCN9d68,375
|
|
222
|
-
angr/analyses/decompiler/presets/basic.py,sha256=
|
|
223
|
-
angr/analyses/decompiler/presets/fast.py,sha256=
|
|
224
|
-
angr/analyses/decompiler/presets/full.py,sha256=
|
|
224
|
+
angr/analyses/decompiler/presets/basic.py,sha256=KDHlMq_XWonN2-JIYYVIhbI6FbfzXttmkgXFrwi5MiA,803
|
|
225
|
+
angr/analyses/decompiler/presets/fast.py,sha256=7C6-7Enha_ZRP-z_1tD3y3tG-FFqFPdp97rCTro0I6o,1535
|
|
226
|
+
angr/analyses/decompiler/presets/full.py,sha256=OJU5vmih0QPzoHWfy4Umwek7RHh6TV7fuUTi5VolDTo,1708
|
|
225
227
|
angr/analyses/decompiler/presets/preset.py,sha256=sTK5fJfx_Cdx0Gjn7y4bOrDp-2eFPeg1e1d5Eyc9uXk,1256
|
|
226
228
|
angr/analyses/decompiler/region_simplifiers/__init__.py,sha256=BSD9osrReTEdapOMmyI1kFiN7AmE1EeJGLBV7i0u-Uc,117
|
|
227
229
|
angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py,sha256=qLs1LxEYHdPrh5c33IdkHJqtjBU7z4Sz6fxOK4Fn0Oc,3816
|
|
@@ -250,10 +252,10 @@ angr/analyses/decompiler/structured_codegen/dummy.py,sha256=JZLeovXE-8C-unp2hbej
|
|
|
250
252
|
angr/analyses/decompiler/structured_codegen/dwarf_import.py,sha256=J6V40RuIyKXN7r6ESftIYfoREgmgFavnUL5m3lyTzlM,7072
|
|
251
253
|
angr/analyses/decompiler/structuring/__init__.py,sha256=u2SGBezMdqQF_2ixo8wr66vCMedAMY-cSjQyq2m-nR8,711
|
|
252
254
|
angr/analyses/decompiler/structuring/dream.py,sha256=mPNNsNvNb-LoDcoU_HjUejRytIFY_ZyCAbK4tNq_5lM,48254
|
|
253
|
-
angr/analyses/decompiler/structuring/phoenix.py,sha256
|
|
254
|
-
angr/analyses/decompiler/structuring/recursive_structurer.py,sha256=
|
|
255
|
+
angr/analyses/decompiler/structuring/phoenix.py,sha256=-DkejyxETWXqGGdDw2-HBqlMgNUkVpApyyMpPforhSA,125114
|
|
256
|
+
angr/analyses/decompiler/structuring/recursive_structurer.py,sha256=wxMiixVpmao1Rpuo3wN-gxkPh2YrgTTW4usgtdjdY9E,7150
|
|
255
257
|
angr/analyses/decompiler/structuring/sailr.py,sha256=6lM9cK3iU1kQ_eki7v1Z2VxTiX5OwQzIRF_BbEsw67Q,5721
|
|
256
|
-
angr/analyses/decompiler/structuring/structurer_base.py,sha256=
|
|
258
|
+
angr/analyses/decompiler/structuring/structurer_base.py,sha256=b2fGaDOYy_XdgbOHsKIalJWVTXEt4zDK7w3IO-ZgIjI,43276
|
|
257
259
|
angr/analyses/decompiler/structuring/structurer_nodes.py,sha256=a916imPog4YCCtWtzcnHIQMPLEC73C5t-zSvx9mnvGk,12081
|
|
258
260
|
angr/analyses/deobfuscator/__init__.py,sha256=dkmq-mm3V6kiuchwUZCXr3bDRAEB1-zsPHeEt54tlUE,648
|
|
259
261
|
angr/analyses/deobfuscator/api_obf_finder.py,sha256=WWl55WESeAwcJMrJPX0LqGKN0druzWz--PsG79IliQA,13241
|
|
@@ -1351,9 +1353,9 @@ angr/utils/timing.py,sha256=ELuRPzdRSHzOATgtAzTFByMlVr021ypMrsvtpopreLg,1481
|
|
|
1351
1353
|
angr/utils/ssa/__init__.py,sha256=Sz9zQVnvtmCbJJYeTG_k2JxcZtgxvIxap-KqzvRnIFQ,8015
|
|
1352
1354
|
angr/utils/ssa/tmp_uses_collector.py,sha256=rSpvMxBHzg-tmvhsfjn3iLyPEKzaZN-xpQrdslMq3J4,793
|
|
1353
1355
|
angr/utils/ssa/vvar_uses_collector.py,sha256=8gfAWdRMz73Deh-ZshDM3GPAot9Lf-rHzCiaCil0hlE,1342
|
|
1354
|
-
angr-9.2.
|
|
1355
|
-
angr-9.2.
|
|
1356
|
-
angr-9.2.
|
|
1357
|
-
angr-9.2.
|
|
1358
|
-
angr-9.2.
|
|
1359
|
-
angr-9.2.
|
|
1356
|
+
angr-9.2.129.dist-info/LICENSE,sha256=cgL_ho5B1NH8UxwtBuqThRWdjear8b7hktycaS1sz6g,1327
|
|
1357
|
+
angr-9.2.129.dist-info/METADATA,sha256=WOdMRFoJxdkUHH8TILuVOxyo2fJZ2amFBMlZdEZpkbg,4762
|
|
1358
|
+
angr-9.2.129.dist-info/WHEEL,sha256=4Gyx0AkwVnkmVh7urC5vYOQGgSc_AOR8LpgZGh-WWPI,109
|
|
1359
|
+
angr-9.2.129.dist-info/entry_points.txt,sha256=Vjh1C8PMyr5dZFMnik5WkEP01Uwr2T73I3a6N32sgQU,44
|
|
1360
|
+
angr-9.2.129.dist-info/top_level.txt,sha256=dKw0KWTbwLXytFvv15oAAG4sUs3ey47tt6DorJG9-hw,5
|
|
1361
|
+
angr-9.2.129.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|