angr 9.2.138__py3-none-macosx_11_0_arm64.whl → 9.2.139__py3-none-macosx_11_0_arm64.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/fact_collector.py +59 -12
- angr/analyses/calling_convention/utils.py +2 -2
- angr/analyses/cfg/cfg_fast.py +12 -4
- angr/analyses/decompiler/ail_simplifier.py +14 -3
- angr/analyses/decompiler/block_simplifier.py +0 -2
- angr/analyses/decompiler/callsite_maker.py +80 -14
- angr/analyses/decompiler/clinic.py +31 -37
- angr/analyses/decompiler/condition_processor.py +2 -2
- angr/analyses/decompiler/decompiler.py +2 -0
- angr/analyses/decompiler/dephication/rewriting_engine.py +16 -7
- angr/analyses/decompiler/optimization_passes/__init__.py +3 -0
- angr/analyses/decompiler/optimization_passes/condition_constprop.py +149 -0
- angr/analyses/decompiler/optimization_passes/deadblock_remover.py +12 -3
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +5 -2
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +15 -7
- angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +7 -10
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +12 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +61 -25
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +50 -1
- angr/analyses/decompiler/presets/fast.py +2 -0
- angr/analyses/decompiler/presets/full.py +2 -0
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +4 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +20 -2
- angr/analyses/decompiler/ssailification/traversal_engine.py +4 -3
- angr/analyses/decompiler/structured_codegen/c.py +10 -3
- angr/analyses/decompiler/structuring/dream.py +7 -2
- angr/analyses/decompiler/structuring/phoenix.py +101 -49
- angr/analyses/decompiler/structuring/structurer_base.py +85 -36
- angr/analyses/decompiler/structuring/structurer_nodes.py +3 -1
- angr/analyses/deobfuscator/api_obf_finder.py +6 -1
- angr/analyses/deobfuscator/api_obf_type2_finder.py +158 -0
- angr/analyses/s_propagator.py +127 -50
- angr/analyses/s_reaching_definitions/s_rda_view.py +2 -2
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +3 -1
- angr/analyses/variable_recovery/engine_ail.py +1 -1
- angr/analyses/variable_recovery/engine_base.py +55 -62
- angr/analyses/variable_recovery/engine_vex.py +1 -1
- angr/analyses/variable_recovery/irsb_scanner.py +2 -2
- angr/calling_conventions.py +66 -9
- angr/engines/engine.py +2 -18
- angr/engines/light/engine.py +3 -8
- angr/engines/pcode/emulate.py +2 -2
- angr/engines/pcode/lifter.py +2 -2
- angr/engines/successors.py +1 -8
- angr/engines/vex/lifter.py +2 -2
- angr/engines/vex/light/light.py +2 -2
- angr/knowledge_plugins/cfg/cfg_model.py +3 -2
- angr/knowledge_plugins/labels.py +2 -2
- angr/knowledge_plugins/obfuscations.py +1 -0
- angr/knowledge_plugins/xrefs/xref_manager.py +4 -0
- angr/lib/angr_native.dylib +0 -0
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/METADATA +6 -6
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/RECORD +59 -57
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/LICENSE +0 -0
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/WHEEL +0 -0
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/entry_points.txt +0 -0
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/top_level.txt +0 -0
|
@@ -241,6 +241,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
241
241
|
def _match_cyclic_schemas(self, node, head, graph, full_graph) -> bool:
|
|
242
242
|
matched, loop_node, successor_node = self._match_cyclic_while(node, head, graph, full_graph)
|
|
243
243
|
if matched:
|
|
244
|
+
assert loop_node is not None and successor_node is not None
|
|
244
245
|
# traverse this node and rewrite all conditional jumps that go outside the loop to breaks
|
|
245
246
|
self._rewrite_conditional_jumps_to_breaks(loop_node.sequence_node, [successor_node.addr])
|
|
246
247
|
# traverse this node and rewrite all jumps that go to the beginning of the loop to continue
|
|
@@ -249,6 +250,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
249
250
|
|
|
250
251
|
matched, loop_node, successor_node = self._match_cyclic_dowhile(node, head, graph, full_graph)
|
|
251
252
|
if matched:
|
|
253
|
+
assert loop_node is not None and successor_node is not None
|
|
252
254
|
# traverse this node and rewrite all conditional jumps that go outside the loop to breaks
|
|
253
255
|
self._rewrite_conditional_jumps_to_breaks(loop_node.sequence_node, [successor_node.addr])
|
|
254
256
|
# traverse this node and rewrite all jumps that go to the beginning of the loop to continue
|
|
@@ -260,6 +262,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
260
262
|
node, head, graph, full_graph
|
|
261
263
|
)
|
|
262
264
|
if matched:
|
|
265
|
+
assert loop_node is not None and successor_node is not None
|
|
263
266
|
# traverse this node and rewrite all conditional jumps that go outside the loop to breaks
|
|
264
267
|
self._rewrite_conditional_jumps_to_breaks(loop_node.sequence_node, [successor_node.addr])
|
|
265
268
|
# traverse this node and rewrite all jumps that go to the beginning of the loop to continue
|
|
@@ -268,6 +271,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
268
271
|
|
|
269
272
|
matched, loop_node = self._match_cyclic_natural_loop(node, head, graph, full_graph)
|
|
270
273
|
if matched:
|
|
274
|
+
assert loop_node is not None
|
|
271
275
|
if self._region.successors is not None and len(self._region.successors) == 1:
|
|
272
276
|
# traverse this node and rewrite all conditional jumps that go outside the loop to breaks
|
|
273
277
|
self._rewrite_conditional_jumps_to_breaks(
|
|
@@ -318,7 +322,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
318
322
|
# otherwise it's a do-while loop
|
|
319
323
|
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, head_block, left)
|
|
320
324
|
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, head_block, right)
|
|
321
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right):
|
|
325
|
+
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
322
326
|
# c = !c
|
|
323
327
|
if head_block_idx == 0:
|
|
324
328
|
self._remove_first_statement_if_jump(head_block)
|
|
@@ -346,7 +350,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
346
350
|
if head_block is not None:
|
|
347
351
|
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, head_block, left)
|
|
348
352
|
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, head_block, right)
|
|
349
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right):
|
|
353
|
+
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
350
354
|
# c = !c
|
|
351
355
|
if PhoenixStructurer._is_single_statement_block(node):
|
|
352
356
|
# the single-statement-block check is to ensure we don't execute any code before the
|
|
@@ -366,6 +370,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
366
370
|
return True, loop_node, right
|
|
367
371
|
# we generate a while-true loop instead
|
|
368
372
|
last_stmt = self._remove_last_statement_if_jump(head_block)
|
|
373
|
+
assert last_stmt is not None
|
|
369
374
|
cond_jump = Jump(
|
|
370
375
|
None,
|
|
371
376
|
Const(None, None, right.addr, self.project.arch.bits),
|
|
@@ -394,7 +399,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
394
399
|
if head_block is not None:
|
|
395
400
|
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, head_block, left)
|
|
396
401
|
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, head_block, right)
|
|
397
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right):
|
|
402
|
+
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
398
403
|
# c = !c
|
|
399
404
|
self._remove_last_statement_if_jump(head_block)
|
|
400
405
|
cond_break = ConditionalBreakNode(node.addr, edge_cond_right, right.addr)
|
|
@@ -426,6 +431,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
426
431
|
return False, None, None
|
|
427
432
|
|
|
428
433
|
loop_cond = None
|
|
434
|
+
successor_node = None
|
|
435
|
+
succ_node_is_true_node = None
|
|
429
436
|
if (
|
|
430
437
|
isinstance(node, SequenceNode)
|
|
431
438
|
and node.nodes
|
|
@@ -436,21 +443,27 @@ class PhoenixStructurer(StructurerBase):
|
|
|
436
443
|
and node.nodes[-1].true_node is not None
|
|
437
444
|
and node.nodes[-1].false_node is not None
|
|
438
445
|
):
|
|
439
|
-
|
|
440
|
-
#
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
except EmptyBlockNotice:
|
|
445
|
-
last_stmt = None
|
|
446
|
-
if last_stmt is not None and isinstance(last_stmt, Return):
|
|
446
|
+
# try both true node and false node; pick the first node with only Returns as last statements as the
|
|
447
|
+
# successor.
|
|
448
|
+
if self._cyclic_while_with_single_successor_must_return(node.nodes[-1].true_node):
|
|
449
|
+
succ_node_is_true_node = True
|
|
450
|
+
successor_node = node.nodes[-1].true_node
|
|
447
451
|
loop_cond = claripy.Not(node.nodes[-1].condition)
|
|
452
|
+
elif self._cyclic_while_with_single_successor_must_return(node.nodes[-1].false_node):
|
|
453
|
+
succ_node_is_true_node = False
|
|
454
|
+
successor_node = node.nodes[-1].false_node
|
|
455
|
+
loop_cond = node.nodes[-1].condition
|
|
456
|
+
else:
|
|
457
|
+
loop_cond = None
|
|
448
458
|
|
|
449
459
|
if loop_cond is None:
|
|
450
460
|
return False, None, None
|
|
451
461
|
|
|
452
462
|
node_copy = node.copy()
|
|
453
|
-
|
|
463
|
+
# replace the last node with the intended successor node
|
|
464
|
+
node_copy.nodes[-1] = (
|
|
465
|
+
node_copy.nodes[-1].false_node if succ_node_is_true_node else node_copy.nodes[-1].true_node
|
|
466
|
+
)
|
|
454
467
|
# check if there is a cycle that starts with node and ends with node
|
|
455
468
|
next_node = node
|
|
456
469
|
seq_node = SequenceNode(node.addr, nodes=[node_copy])
|
|
@@ -487,6 +500,15 @@ class PhoenixStructurer(StructurerBase):
|
|
|
487
500
|
|
|
488
501
|
return True, loop_node, successor_node
|
|
489
502
|
|
|
503
|
+
def _cyclic_while_with_single_successor_must_return(self, successor_node: SequenceNode) -> bool:
|
|
504
|
+
try:
|
|
505
|
+
last_stmts = self.cond_proc.get_last_statements(successor_node)
|
|
506
|
+
except EmptyBlockNotice:
|
|
507
|
+
return False
|
|
508
|
+
if not last_stmts:
|
|
509
|
+
return False
|
|
510
|
+
return all(isinstance(stmt, Return) for stmt in last_stmts)
|
|
511
|
+
|
|
490
512
|
def _match_cyclic_dowhile(self, node, head, graph, full_graph) -> tuple[bool, LoopNode | None, BaseNode | None]:
|
|
491
513
|
preds = list(full_graph.predecessors(node))
|
|
492
514
|
succs = list(full_graph.successors(node))
|
|
@@ -504,7 +526,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
504
526
|
if succ_block is not None:
|
|
505
527
|
edge_cond_succhead = self.cond_proc.recover_edge_condition(full_graph, succ_block, node)
|
|
506
528
|
edge_cond_succout = self.cond_proc.recover_edge_condition(full_graph, succ_block, out_node)
|
|
507
|
-
if claripy.is_true(claripy.Not(edge_cond_succhead) == edge_cond_succout):
|
|
529
|
+
if claripy.is_true(claripy.Not(edge_cond_succhead) == edge_cond_succout): # type: ignore
|
|
508
530
|
# c = !c
|
|
509
531
|
self._remove_last_statement_if_jump(succ)
|
|
510
532
|
drop_succ = False
|
|
@@ -543,7 +565,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
543
565
|
# possible candidate
|
|
544
566
|
edge_cond_head = self.cond_proc.recover_edge_condition(full_graph, node, node)
|
|
545
567
|
edge_cond_head_succ = self.cond_proc.recover_edge_condition(full_graph, node, succ)
|
|
546
|
-
if claripy.is_true(claripy.Not(edge_cond_head) == edge_cond_head_succ):
|
|
568
|
+
if claripy.is_true(claripy.Not(edge_cond_head) == edge_cond_head_succ): # type: ignore
|
|
547
569
|
# c = !c
|
|
548
570
|
self._remove_last_statement_if_jump(node)
|
|
549
571
|
seq_node = SequenceNode(node.addr, nodes=[node]) if not isinstance(node, SequenceNode) else node
|
|
@@ -617,9 +639,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
617
639
|
|
|
618
640
|
def _refine_cyclic_core(self, loop_head) -> bool:
|
|
619
641
|
graph: networkx.DiGraph = self._region.graph
|
|
620
|
-
fullgraph: networkx.DiGraph =
|
|
621
|
-
|
|
622
|
-
|
|
642
|
+
fullgraph: networkx.DiGraph = (
|
|
643
|
+
self._region.graph_with_successors
|
|
644
|
+
if self._region.graph_with_successors is not None
|
|
645
|
+
else networkx.DiGraph(self._region.graph)
|
|
646
|
+
)
|
|
623
647
|
|
|
624
648
|
# check if there is an out-going edge from the loop head
|
|
625
649
|
head_succs = list(fullgraph.successors(loop_head))
|
|
@@ -638,6 +662,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
638
662
|
# for now, we handle the most common case: both successors exist in the graph of the parent region, and
|
|
639
663
|
# one successor has a path to the other successor
|
|
640
664
|
if is_while and is_dowhile and self._parent_region is not None:
|
|
665
|
+
assert result_while is not None and result_dowhile is not None
|
|
641
666
|
succ_while = result_while[-1]
|
|
642
667
|
succ_dowhile = result_dowhile[-1]
|
|
643
668
|
if succ_while in self._parent_region.graph and succ_dowhile in self._parent_region.graph:
|
|
@@ -651,9 +676,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
651
676
|
is_while = False
|
|
652
677
|
|
|
653
678
|
if is_while:
|
|
679
|
+
assert result_while is not None
|
|
654
680
|
loop_type = "while"
|
|
655
681
|
continue_edges, outgoing_edges, continue_node, successor = result_while
|
|
656
682
|
elif is_dowhile:
|
|
683
|
+
assert result_dowhile is not None
|
|
657
684
|
loop_type = "do-while"
|
|
658
685
|
continue_edges, outgoing_edges, continue_node, successor = result_dowhile
|
|
659
686
|
|
|
@@ -736,6 +763,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
736
763
|
# unwanted results, e.g., inserting a break (that's intended to break out of the loop) inside a
|
|
737
764
|
# switch-case that is nested within a loop.
|
|
738
765
|
last_src_stmt = self.cond_proc.get_last_statement(src_block)
|
|
766
|
+
assert last_src_stmt is not None
|
|
739
767
|
break_cond = self.cond_proc.recover_edge_condition(fullgraph, src_block, dst)
|
|
740
768
|
if claripy.is_true(break_cond):
|
|
741
769
|
break_stmt = Jump(
|
|
@@ -761,7 +789,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
761
789
|
)
|
|
762
790
|
new_node = SequenceNode(src_block.addr, nodes=[src_block, break_node])
|
|
763
791
|
if has_continue:
|
|
764
|
-
if self.is_a_jump_target(
|
|
792
|
+
if continue_node.addr is not None and self.is_a_jump_target(
|
|
793
|
+
last_src_stmt, continue_node.addr
|
|
794
|
+
):
|
|
765
795
|
# instead of a conditional break node, we should insert a condition node instead
|
|
766
796
|
break_stmt = Jump(
|
|
767
797
|
None,
|
|
@@ -817,7 +847,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
817
847
|
if fullgraph.in_degree[dst] == 0:
|
|
818
848
|
# drop this node
|
|
819
849
|
fullgraph.remove_node(dst)
|
|
820
|
-
if dst in self._region.successors:
|
|
850
|
+
if self._region.successors and dst in self._region.successors:
|
|
821
851
|
self._region.successors.remove(dst)
|
|
822
852
|
|
|
823
853
|
if len(continue_edges) > 1:
|
|
@@ -1074,7 +1104,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1074
1104
|
|
|
1075
1105
|
# make a fake jumptable
|
|
1076
1106
|
node_default_addr = None
|
|
1077
|
-
case_entries: dict[int, tuple[int, int | None]] = {}
|
|
1107
|
+
case_entries: dict[int, int | tuple[int, int | None]] = {}
|
|
1078
1108
|
for _, case_value, case_target_addr, case_target_idx, _ in last_stmt.case_addrs:
|
|
1079
1109
|
if isinstance(case_value, str):
|
|
1080
1110
|
if case_value == "default":
|
|
@@ -1127,7 +1157,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1127
1157
|
if self._region.graph_with_successors is not None:
|
|
1128
1158
|
self._region.graph_with_successors.remove_node(o)
|
|
1129
1159
|
|
|
1130
|
-
self.
|
|
1160
|
+
switch_end_addr = self._switch_find_switch_end_addr(cases, node_default, {nn.addr for nn in self._region.graph})
|
|
1161
|
+
if switch_end_addr is not None:
|
|
1162
|
+
self._switch_handle_gotos(cases, node_default, switch_end_addr)
|
|
1131
1163
|
return True
|
|
1132
1164
|
|
|
1133
1165
|
def _match_acyclic_switch_cases_address_loaded_from_memory(self, node, graph, full_graph, jump_tables) -> bool:
|
|
@@ -1136,6 +1168,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1136
1168
|
except EmptyBlockNotice:
|
|
1137
1169
|
return False
|
|
1138
1170
|
|
|
1171
|
+
if last_stmt is None:
|
|
1172
|
+
return False
|
|
1173
|
+
|
|
1139
1174
|
successor_addrs = extract_jump_targets(last_stmt)
|
|
1140
1175
|
if len(successor_addrs) != 2:
|
|
1141
1176
|
return False
|
|
@@ -1222,7 +1257,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1222
1257
|
switch_end_addr = node_b_addr
|
|
1223
1258
|
else:
|
|
1224
1259
|
# we don't know what the end address of this switch-case structure is. let's figure it out
|
|
1225
|
-
switch_end_addr =
|
|
1260
|
+
switch_end_addr = self._switch_find_switch_end_addr(
|
|
1261
|
+
cases, node_default, {nn.addr for nn in self._region.graph}
|
|
1262
|
+
)
|
|
1226
1263
|
to_remove.add(node_default)
|
|
1227
1264
|
|
|
1228
1265
|
to_remove.add(node_a) # add node_a
|
|
@@ -1243,7 +1280,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1243
1280
|
|
|
1244
1281
|
# fully structured into a switch-case. remove node from switch_case_known_heads
|
|
1245
1282
|
self.switch_case_known_heads.remove(node)
|
|
1246
|
-
|
|
1283
|
+
if switch_end_addr is not None:
|
|
1284
|
+
self._switch_handle_gotos(cases, node_default, switch_end_addr)
|
|
1247
1285
|
|
|
1248
1286
|
return True
|
|
1249
1287
|
|
|
@@ -1311,7 +1349,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1311
1349
|
)
|
|
1312
1350
|
|
|
1313
1351
|
assert node_default is None
|
|
1314
|
-
switch_end_addr =
|
|
1352
|
+
switch_end_addr = self._switch_find_switch_end_addr(cases, node_default, {nn.addr for nn in self._region.graph})
|
|
1315
1353
|
|
|
1316
1354
|
r = self._make_switch_cases_core(
|
|
1317
1355
|
node,
|
|
@@ -1330,7 +1368,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1330
1368
|
|
|
1331
1369
|
# fully structured into a switch-case. remove node from switch_case_known_heads
|
|
1332
1370
|
self.switch_case_known_heads.remove(node)
|
|
1333
|
-
|
|
1371
|
+
if switch_end_addr is not None:
|
|
1372
|
+
self._switch_handle_gotos(cases, node_default, switch_end_addr)
|
|
1334
1373
|
|
|
1335
1374
|
return True
|
|
1336
1375
|
|
|
@@ -1431,7 +1470,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1431
1470
|
graph,
|
|
1432
1471
|
full_graph,
|
|
1433
1472
|
) -> tuple[OrderedDict, Any, set[Any]]:
|
|
1434
|
-
cases: OrderedDict[int | tuple[int], SequenceNode] = OrderedDict()
|
|
1473
|
+
cases: OrderedDict[int | tuple[int, ...], SequenceNode] = OrderedDict()
|
|
1435
1474
|
to_remove = set()
|
|
1436
1475
|
|
|
1437
1476
|
# it is possible that the default node gets duplicated by other analyses and creates a default node (addr.a)
|
|
@@ -1719,6 +1758,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1719
1758
|
succs = list(full_graph.successors(start_node))
|
|
1720
1759
|
if len(succs) == 2:
|
|
1721
1760
|
left, right = succs
|
|
1761
|
+
if left.addr > right.addr:
|
|
1762
|
+
left, right = right, left
|
|
1722
1763
|
if self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(
|
|
1723
1764
|
full_graph, left
|
|
1724
1765
|
) or self._is_switch_cases_address_loaded_from_memory_head_or_jumpnode(full_graph, right):
|
|
@@ -1747,7 +1788,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1747
1788
|
):
|
|
1748
1789
|
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
1749
1790
|
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
1750
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right):
|
|
1791
|
+
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
1751
1792
|
# c = !c
|
|
1752
1793
|
last_if_jump = self._remove_last_statement_if_jump(start_node)
|
|
1753
1794
|
new_cond_node = ConditionNode(
|
|
@@ -1789,7 +1830,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1789
1830
|
) and not self._is_node_unstructured_switch_case_head(right):
|
|
1790
1831
|
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
1791
1832
|
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
1792
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right):
|
|
1833
|
+
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
1793
1834
|
# c = !c
|
|
1794
1835
|
last_if_jump = self._remove_last_statement_if_jump(start_node)
|
|
1795
1836
|
new_cond_node = ConditionNode(
|
|
@@ -1822,7 +1863,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1822
1863
|
):
|
|
1823
1864
|
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
1824
1865
|
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
1825
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right):
|
|
1866
|
+
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
1826
1867
|
# c = !c
|
|
1827
1868
|
last_if_jump = self._remove_last_statement_if_jump(start_node)
|
|
1828
1869
|
new_cond_node = ConditionNode(
|
|
@@ -1857,7 +1898,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1857
1898
|
):
|
|
1858
1899
|
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
1859
1900
|
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
1860
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right):
|
|
1901
|
+
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
1861
1902
|
# c = !c
|
|
1862
1903
|
try:
|
|
1863
1904
|
last_stmt = self.cond_proc.get_last_statement(start_node)
|
|
@@ -1876,7 +1917,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1876
1917
|
self._remove_last_statement_if_jump(start_node)
|
|
1877
1918
|
# add a goto node at the end
|
|
1878
1919
|
new_jump_node = Block(
|
|
1879
|
-
new_cond_node.addr,
|
|
1920
|
+
new_cond_node.addr if new_cond_node.addr is not None else 0x7EFF_FFFF,
|
|
1880
1921
|
0,
|
|
1881
1922
|
statements=[
|
|
1882
1923
|
Jump(
|
|
@@ -2162,7 +2203,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2162
2203
|
):
|
|
2163
2204
|
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
2164
2205
|
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
2165
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right):
|
|
2206
|
+
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
2166
2207
|
# c0 = !c0
|
|
2167
2208
|
left_succs = list(full_graph.successors(left))
|
|
2168
2209
|
if len(left_succs) == 2 and right in left_succs:
|
|
@@ -2171,7 +2212,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2171
2212
|
# there must be an edge between right and other_succ
|
|
2172
2213
|
edge_cond_left_right = self.cond_proc.recover_edge_condition(full_graph, left, right)
|
|
2173
2214
|
edge_cond_left_other = self.cond_proc.recover_edge_condition(full_graph, left, other_succ)
|
|
2174
|
-
if claripy.is_true(
|
|
2215
|
+
if claripy.is_true(
|
|
2216
|
+
claripy.Not(edge_cond_left_right) == edge_cond_left_other # type: ignore
|
|
2217
|
+
):
|
|
2175
2218
|
# c1 = !c1
|
|
2176
2219
|
return left, edge_cond_left, right, edge_cond_left_right, other_succ
|
|
2177
2220
|
return None
|
|
@@ -2211,7 +2254,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2211
2254
|
):
|
|
2212
2255
|
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
2213
2256
|
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
2214
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right):
|
|
2257
|
+
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
2215
2258
|
# c0 = !c0
|
|
2216
2259
|
right_succs = list(full_graph.successors(right))
|
|
2217
2260
|
left_succs = list(full_graph.successors(left))
|
|
@@ -2220,7 +2263,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2220
2263
|
if len([succ for succ in left_succs if succ is not else_node]) == 1:
|
|
2221
2264
|
edge_cond_right_left = self.cond_proc.recover_edge_condition(full_graph, right, left)
|
|
2222
2265
|
edge_cond_right_else = self.cond_proc.recover_edge_condition(full_graph, right, else_node)
|
|
2223
|
-
if claripy.is_true(
|
|
2266
|
+
if claripy.is_true(
|
|
2267
|
+
claripy.Not(edge_cond_right_left) == edge_cond_right_else # type: ignore
|
|
2268
|
+
):
|
|
2224
2269
|
# c1 = !c1
|
|
2225
2270
|
return left, edge_cond_left, right, edge_cond_right_left, else_node
|
|
2226
2271
|
return None
|
|
@@ -2316,7 +2361,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2316
2361
|
return left, edge_cond_left, right, edge_cond_left_right, else_node
|
|
2317
2362
|
return None
|
|
2318
2363
|
|
|
2319
|
-
def _last_resort_refinement(self, head, graph: networkx.DiGraph, full_graph: networkx.DiGraph
|
|
2364
|
+
def _last_resort_refinement(self, head, graph: networkx.DiGraph, full_graph: networkx.DiGraph) -> bool:
|
|
2320
2365
|
if self._improve_algorithm:
|
|
2321
2366
|
while self._edge_virtualization_hints:
|
|
2322
2367
|
src, dst = self._edge_virtualization_hints.pop(0)
|
|
@@ -2461,7 +2506,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2461
2506
|
|
|
2462
2507
|
@staticmethod
|
|
2463
2508
|
def _find_node_going_to_dst(
|
|
2464
|
-
node:
|
|
2509
|
+
node: BaseNode,
|
|
2465
2510
|
dst: Block | BaseNode,
|
|
2466
2511
|
last=True,
|
|
2467
2512
|
condjump_only=False,
|
|
@@ -2477,6 +2522,14 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2477
2522
|
dst_addr = dst.addr
|
|
2478
2523
|
dst_idx = dst.idx if isinstance(dst, Block) else ...
|
|
2479
2524
|
|
|
2525
|
+
class _Holder:
|
|
2526
|
+
"""
|
|
2527
|
+
Holds parent_and_block and is accessible from within the handlers.
|
|
2528
|
+
"""
|
|
2529
|
+
|
|
2530
|
+
parent_and_block: list[tuple[int, Any, Block | MultiNode | BreakNode]] = []
|
|
2531
|
+
block_id: int = -1
|
|
2532
|
+
|
|
2480
2533
|
def _check(last_stmt):
|
|
2481
2534
|
return (
|
|
2482
2535
|
(
|
|
@@ -2512,34 +2565,34 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2512
2565
|
first_stmt = first_nonlabel_nonphi_statement(block)
|
|
2513
2566
|
if first_stmt is not None:
|
|
2514
2567
|
# this block has content. increment the block ID counter
|
|
2515
|
-
|
|
2568
|
+
_Holder.block_id += 1
|
|
2516
2569
|
|
|
2517
2570
|
if _check(first_stmt):
|
|
2518
|
-
|
|
2571
|
+
_Holder.parent_and_block.append((_Holder.block_id, parent, block))
|
|
2519
2572
|
elif len(block.statements) > 1:
|
|
2520
2573
|
last_stmt = block.statements[-1]
|
|
2521
2574
|
if _check(last_stmt) or (
|
|
2522
2575
|
not isinstance(last_stmt, (Jump, ConditionalJump))
|
|
2523
2576
|
and block.addr + block.original_size == dst_addr
|
|
2524
2577
|
):
|
|
2525
|
-
|
|
2578
|
+
_Holder.parent_and_block.append((_Holder.block_id, parent, block))
|
|
2526
2579
|
|
|
2527
2580
|
def _handle_MultiNode(block: MultiNode, parent=None, **kwargs): # pylint:disable=unused-argument
|
|
2528
2581
|
if block.nodes and isinstance(block.nodes[-1], Block) and block.nodes[-1].statements:
|
|
2529
2582
|
first_stmt = first_nonlabel_nonphi_statement(block)
|
|
2530
2583
|
if first_stmt is not None:
|
|
2531
2584
|
# this block has content. increment the block ID counter
|
|
2532
|
-
|
|
2585
|
+
_Holder.block_id += 1
|
|
2533
2586
|
if _check(block.nodes[-1].statements[-1]):
|
|
2534
|
-
|
|
2587
|
+
_Holder.parent_and_block.append((_Holder.block_id, parent, block))
|
|
2535
2588
|
|
|
2536
2589
|
def _handle_BreakNode(break_node: BreakNode, parent=None, **kwargs): # pylint:disable=unused-argument
|
|
2537
|
-
|
|
2590
|
+
_Holder.block_id += 1
|
|
2538
2591
|
if break_node.target == dst_addr or (
|
|
2539
2592
|
isinstance(break_node.target, Const) and break_node.target.value == dst_addr
|
|
2540
2593
|
):
|
|
2541
2594
|
# FIXME: idx is ignored
|
|
2542
|
-
|
|
2595
|
+
_Holder.parent_and_block.append((_Holder.block_id, parent, break_node))
|
|
2543
2596
|
|
|
2544
2597
|
walker = SequenceWalker(
|
|
2545
2598
|
handlers={
|
|
@@ -2550,14 +2603,13 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2550
2603
|
update_seqnode_in_place=False,
|
|
2551
2604
|
force_forward_scan=True,
|
|
2552
2605
|
)
|
|
2553
|
-
|
|
2554
|
-
walker.block_id = -1
|
|
2606
|
+
_Holder.block_id = -1
|
|
2555
2607
|
walker.walk(node)
|
|
2556
|
-
if not
|
|
2608
|
+
if not _Holder.parent_and_block:
|
|
2557
2609
|
return None, None, None
|
|
2558
2610
|
if last:
|
|
2559
|
-
return
|
|
2560
|
-
return
|
|
2611
|
+
return _Holder.parent_and_block[-1]
|
|
2612
|
+
return _Holder.parent_and_block[0]
|
|
2561
2613
|
|
|
2562
2614
|
@staticmethod
|
|
2563
2615
|
def _unpack_sequencenode_head(graph: networkx.DiGraph, seq: SequenceNode, new_seq=None):
|