angr 9.2.160__cp310-abi3-macosx_11_0_arm64.whl → 9.2.162__cp310-abi3-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 +4 -1
- angr/analyses/analysis.py +0 -1
- angr/analyses/cfg/cfg_base.py +5 -1
- angr/analyses/decompiler/ail_simplifier.py +101 -2
- angr/analyses/decompiler/block_simplifier.py +13 -8
- angr/analyses/decompiler/clinic.py +1 -0
- angr/analyses/decompiler/condition_processor.py +24 -0
- angr/analyses/decompiler/counters/call_counter.py +11 -1
- angr/analyses/decompiler/decompiler.py +3 -1
- angr/analyses/decompiler/graph_region.py +11 -2
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +1 -1
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -0
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +31 -11
- angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +2 -0
- angr/analyses/decompiler/peephole_optimizations/__init__.py +4 -4
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +53 -0
- angr/analyses/decompiler/peephole_optimizations/modulo_simplifier.py +89 -0
- angr/analyses/decompiler/peephole_optimizations/{const_mull_a_shift.py → optimized_div_simplifier.py} +139 -25
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +18 -9
- angr/analyses/decompiler/region_simplifiers/goto.py +3 -3
- angr/analyses/decompiler/region_simplifiers/if_.py +2 -2
- angr/analyses/decompiler/region_simplifiers/loop.py +2 -2
- angr/analyses/decompiler/structured_codegen/c.py +3 -3
- angr/analyses/decompiler/structuring/dream.py +1 -1
- angr/analyses/decompiler/structuring/phoenix.py +138 -99
- angr/analyses/decompiler/structuring/recursive_structurer.py +3 -2
- angr/analyses/decompiler/structuring/sailr.py +51 -43
- angr/analyses/decompiler/structuring/structurer_base.py +2 -3
- angr/analyses/deobfuscator/string_obf_opt_passes.py +1 -1
- angr/analyses/disassembly.py +1 -1
- angr/analyses/reaching_definitions/function_handler.py +1 -0
- angr/analyses/s_propagator.py +2 -2
- angr/analyses/s_reaching_definitions/s_rda_model.py +1 -0
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +5 -2
- angr/analyses/variable_recovery/engine_base.py +17 -1
- angr/analyses/variable_recovery/variable_recovery_base.py +30 -2
- angr/analyses/variable_recovery/variable_recovery_fast.py +11 -2
- angr/emulator.py +143 -0
- angr/engines/concrete.py +66 -0
- angr/engines/icicle.py +66 -30
- angr/exploration_techniques/driller_core.py +2 -2
- angr/knowledge_plugins/functions/function.py +1 -1
- angr/knowledge_plugins/functions/function_manager.py +1 -2
- angr/project.py +7 -0
- angr/rustylib.abi3.so +0 -0
- angr/sim_type.py +16 -8
- angr/simos/javavm.py +1 -1
- angr/unicornlib.dylib +0 -0
- angr/utils/graph.py +48 -13
- angr/utils/library.py +13 -12
- angr/utils/ssa/__init__.py +57 -5
- {angr-9.2.160.dist-info → angr-9.2.162.dist-info}/METADATA +5 -5
- {angr-9.2.160.dist-info → angr-9.2.162.dist-info}/RECORD +57 -55
- angr/analyses/decompiler/peephole_optimizations/a_sub_a_div_const_mul_const.py +0 -57
- {angr-9.2.160.dist-info → angr-9.2.162.dist-info}/WHEEL +0 -0
- {angr-9.2.160.dist-info → angr-9.2.162.dist-info}/entry_points.txt +0 -0
- {angr-9.2.160.dist-info → angr-9.2.162.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.160.dist-info → angr-9.2.162.dist-info}/top_level.txt +0 -0
|
@@ -11,7 +11,7 @@ import networkx
|
|
|
11
11
|
import claripy
|
|
12
12
|
from angr.ailment.block import Block
|
|
13
13
|
from angr.ailment.statement import Statement, ConditionalJump, Jump, Label, Return
|
|
14
|
-
from angr.ailment.expression import Const, UnaryOp, MultiStatementExpression
|
|
14
|
+
from angr.ailment.expression import Const, UnaryOp, MultiStatementExpression, BinaryOp
|
|
15
15
|
|
|
16
16
|
from angr.utils.graph import GraphUtils
|
|
17
17
|
from angr.utils.ail import is_phi_assignment, is_head_controlled_loop_block
|
|
@@ -126,6 +126,12 @@ class PhoenixStructurer(StructurerBase):
|
|
|
126
126
|
self._improve_algorithm = improve_algorithm
|
|
127
127
|
self._edge_virtualization_hints = []
|
|
128
128
|
|
|
129
|
+
# node_order keeps a dictionary of nodes and their order in a quasi-topological sort of the region full graph
|
|
130
|
+
# (graph_with_successors). _generate_node_order() initializes this dictionary. we then update this dictionary
|
|
131
|
+
# when new nodes are created. we do not populate this dictionary when working on acyclic graphs because it's
|
|
132
|
+
# not used for acyclic graphs.
|
|
133
|
+
self._node_order: dict[Any, int] | None = None
|
|
134
|
+
|
|
129
135
|
self._use_multistmtexprs = use_multistmtexprs
|
|
130
136
|
self._multistmtexpr_stmt_threshold = multistmtexpr_stmt_threshold
|
|
131
137
|
self._analyze()
|
|
@@ -221,8 +227,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
221
227
|
|
|
222
228
|
def _analyze_cyclic(self) -> bool:
|
|
223
229
|
any_matches = False
|
|
224
|
-
|
|
225
|
-
|
|
230
|
+
|
|
231
|
+
if self._node_order is None:
|
|
232
|
+
self._generate_node_order()
|
|
233
|
+
acyclic_graph = to_acyclic_graph(self._region.graph, node_order=self._node_order)
|
|
234
|
+
for node in list(GraphUtils.dfs_postorder_nodes_deterministic(acyclic_graph, self._region.head)):
|
|
226
235
|
if node not in self._region.graph:
|
|
227
236
|
continue
|
|
228
237
|
matched = self._match_cyclic_schemas(
|
|
@@ -323,10 +332,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
323
332
|
# it's a while loop if the conditional jump (or the head block) is at the beginning of node
|
|
324
333
|
loop_type = "while" if head_block_idx == 0 else "do-while"
|
|
325
334
|
# otherwise it's a do-while loop
|
|
326
|
-
|
|
327
|
-
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, head_block, right)
|
|
328
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
335
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, head_block, left, right):
|
|
329
336
|
# c = !c
|
|
337
|
+
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, head_block, left)
|
|
330
338
|
if head_block_idx == 0:
|
|
331
339
|
self._remove_first_statement_if_jump(head_block)
|
|
332
340
|
else:
|
|
@@ -351,13 +359,12 @@ class PhoenixStructurer(StructurerBase):
|
|
|
351
359
|
# possible candidate
|
|
352
360
|
_, _, head_block = self._find_node_going_to_dst(node, left, condjump_only=True)
|
|
353
361
|
if head_block is not None:
|
|
354
|
-
|
|
355
|
-
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, head_block, right)
|
|
356
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
362
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, head_block, left, right):
|
|
357
363
|
# c = !c
|
|
358
364
|
if PhoenixStructurer._is_single_statement_block(node):
|
|
359
365
|
# the single-statement-block check is to ensure we don't execute any code before the
|
|
360
366
|
# conditional jump. this way the entire node can be dropped.
|
|
367
|
+
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, head_block, left)
|
|
361
368
|
new_node = SequenceNode(node.addr, nodes=[left])
|
|
362
369
|
loop_node = LoopNode("while", edge_cond_left, new_node, addr=node.addr)
|
|
363
370
|
|
|
@@ -372,6 +379,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
372
379
|
|
|
373
380
|
return True, loop_node, right
|
|
374
381
|
# we generate a while-true loop instead
|
|
382
|
+
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, head_block, right)
|
|
375
383
|
last_stmt = self._remove_last_statement_if_jump(head_block)
|
|
376
384
|
assert last_stmt is not None
|
|
377
385
|
cond_jump = Jump(
|
|
@@ -400,10 +408,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
400
408
|
# while (true) { ...; if (...) break; }
|
|
401
409
|
_, _, head_block = self._find_node_going_to_dst(node, left, condjump_only=True)
|
|
402
410
|
if head_block is not None:
|
|
403
|
-
|
|
404
|
-
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, head_block, right)
|
|
405
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
411
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, head_block, left, right):
|
|
406
412
|
# c = !c
|
|
413
|
+
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, head_block, right)
|
|
407
414
|
self._remove_last_statement_if_jump(head_block)
|
|
408
415
|
cond_break = ConditionalBreakNode(node.addr, edge_cond_right, right.addr)
|
|
409
416
|
new_node = SequenceNode(node.addr, nodes=[node, cond_break, left])
|
|
@@ -501,6 +508,10 @@ class PhoenixStructurer(StructurerBase):
|
|
|
501
508
|
self.replace_nodes(full_graph, node, loop_node, self_loop=False)
|
|
502
509
|
full_graph.add_edge(loop_node, successor_node)
|
|
503
510
|
|
|
511
|
+
if self._node_order is not None:
|
|
512
|
+
self._node_order[loop_node] = self._node_order[node]
|
|
513
|
+
self._node_order[successor_node] = self._node_order[loop_node]
|
|
514
|
+
|
|
504
515
|
return True, loop_node, successor_node
|
|
505
516
|
|
|
506
517
|
def _cyclic_while_with_single_successor_must_return(self, successor_node: SequenceNode) -> bool:
|
|
@@ -527,10 +538,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
527
538
|
# possible candidate
|
|
528
539
|
_, _, succ_block = self._find_node_going_to_dst(succ, out_node, condjump_only=True)
|
|
529
540
|
if succ_block is not None:
|
|
530
|
-
|
|
531
|
-
edge_cond_succout = self.cond_proc.recover_edge_condition(full_graph, succ_block, out_node)
|
|
532
|
-
if claripy.is_true(claripy.Not(edge_cond_succhead) == edge_cond_succout): # type: ignore
|
|
541
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, succ_block, node, out_node):
|
|
533
542
|
# c = !c
|
|
543
|
+
edge_cond_succhead = self.cond_proc.recover_edge_condition(full_graph, succ_block, node)
|
|
534
544
|
self._remove_last_statement_if_jump(succ)
|
|
535
545
|
drop_succ = False
|
|
536
546
|
|
|
@@ -570,10 +580,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
570
580
|
succ = succs[0]
|
|
571
581
|
if not full_graph.has_edge(succ, node):
|
|
572
582
|
# possible candidate
|
|
573
|
-
|
|
574
|
-
edge_cond_head_succ = self.cond_proc.recover_edge_condition(full_graph, node, succ)
|
|
575
|
-
if claripy.is_true(claripy.Not(edge_cond_head) == edge_cond_head_succ): # type: ignore
|
|
583
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, node, node, succ):
|
|
576
584
|
# c = !c
|
|
585
|
+
edge_cond_head = self.cond_proc.recover_edge_condition(full_graph, node, node)
|
|
577
586
|
self._remove_last_statement_if_jump(node)
|
|
578
587
|
seq_node = SequenceNode(node.addr, nodes=[node]) if not isinstance(node, SequenceNode) else node
|
|
579
588
|
loop_node = LoopNode("do-while", edge_cond_head, seq_node, addr=seq_node.addr)
|
|
@@ -1039,7 +1048,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1039
1048
|
|
|
1040
1049
|
self._assert_graph_ok(acyclic_graph, "Removed wrong edges")
|
|
1041
1050
|
|
|
1042
|
-
for node in list(
|
|
1051
|
+
for node in list(GraphUtils.dfs_postorder_nodes_deterministic(acyclic_graph, head)):
|
|
1043
1052
|
if node not in graph:
|
|
1044
1053
|
continue
|
|
1045
1054
|
if graph.has_edge(node, head):
|
|
@@ -1145,6 +1154,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1145
1154
|
node_default = Block(SWITCH_MISSING_DEFAULT_NODE_ADDR, 0, statements=[jmp_to_default_node])
|
|
1146
1155
|
graph.add_edge(node, node_default)
|
|
1147
1156
|
full_graph.add_edge(node, node_default)
|
|
1157
|
+
if self._node_order is not None:
|
|
1158
|
+
self._node_order[node_default] = self._node_order[node]
|
|
1148
1159
|
r = self._make_switch_cases_core(
|
|
1149
1160
|
node,
|
|
1150
1161
|
self.cond_proc.claripy_ast_from_ail_condition(last_stmt.switch_variable),
|
|
@@ -1250,6 +1261,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1250
1261
|
# un-structure IncompleteSwitchCaseNode
|
|
1251
1262
|
if isinstance(node_a, SequenceNode) and node_a.nodes and isinstance(node_a.nodes[0], IncompleteSwitchCaseNode):
|
|
1252
1263
|
_, new_seq_node = self._unpack_sequencenode_head(graph, node_a)
|
|
1264
|
+
if new_seq_node is not None and self._node_order is not None:
|
|
1265
|
+
self._node_order[new_seq_node] = self._node_order[node_a]
|
|
1253
1266
|
self._unpack_sequencenode_head(full_graph, node_a, new_seq=new_seq_node)
|
|
1254
1267
|
# update node_a
|
|
1255
1268
|
node_a = next(iter(nn for nn in graph.nodes if nn.addr == target))
|
|
@@ -1260,6 +1273,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1260
1273
|
self._unpack_incompleteswitchcasenode(full_graph, node_a) # this shall not fail
|
|
1261
1274
|
# update node_a
|
|
1262
1275
|
node_a = next(iter(nn for nn in graph.nodes if nn.addr == target))
|
|
1276
|
+
if self._node_order is not None:
|
|
1277
|
+
self._generate_node_order()
|
|
1263
1278
|
|
|
1264
1279
|
better_node_a = node_a
|
|
1265
1280
|
if isinstance(node_a, SequenceNode) and is_empty_or_label_only_node(node_a.nodes[0]) and len(node_a.nodes) == 2:
|
|
@@ -1604,6 +1619,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1604
1619
|
self.replace_nodes(full_graph, node, new_node)
|
|
1605
1620
|
if out_nodes:
|
|
1606
1621
|
full_graph.add_edge(new_node, out_nodes[0])
|
|
1622
|
+
if self._node_order:
|
|
1623
|
+
self._node_order[new_node] = self._node_order[node]
|
|
1607
1624
|
return True
|
|
1608
1625
|
return False
|
|
1609
1626
|
|
|
@@ -1785,6 +1802,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1785
1802
|
|
|
1786
1803
|
graph.add_edge(head, scnode)
|
|
1787
1804
|
full_graph.add_edge(head, scnode)
|
|
1805
|
+
if self._node_order is not None:
|
|
1806
|
+
self._node_order[scnode] = self._node_order[head]
|
|
1788
1807
|
|
|
1789
1808
|
if out_edges:
|
|
1790
1809
|
# for all out edges going to head, we ensure there is a goto at the end of each corresponding case node
|
|
@@ -1934,10 +1953,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1934
1953
|
and not self._is_node_unstructured_switch_case_head(left)
|
|
1935
1954
|
and not self._is_node_unstructured_switch_case_head(right)
|
|
1936
1955
|
):
|
|
1937
|
-
|
|
1938
|
-
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
1939
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
1956
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, start_node, left, right):
|
|
1940
1957
|
# c = !c
|
|
1958
|
+
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
1941
1959
|
last_if_jump = self._remove_last_statement_if_jump(start_node)
|
|
1942
1960
|
new_cond_node = ConditionNode(
|
|
1943
1961
|
last_if_jump.ins_addr if last_if_jump is not None else start_node.addr,
|
|
@@ -1976,10 +1994,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1976
1994
|
if not self._is_node_unstructured_switch_case_head(
|
|
1977
1995
|
left
|
|
1978
1996
|
) and not self._is_node_unstructured_switch_case_head(right):
|
|
1979
|
-
|
|
1980
|
-
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
1981
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
1997
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, start_node, left, right):
|
|
1982
1998
|
# c = !c
|
|
1999
|
+
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
1983
2000
|
last_if_jump = self._remove_last_statement_if_jump(start_node)
|
|
1984
2001
|
new_cond_node = ConditionNode(
|
|
1985
2002
|
last_if_jump.ins_addr if last_if_jump is not None else start_node.addr,
|
|
@@ -2009,10 +2026,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2009
2026
|
and full_graph.in_degree[left] == 1
|
|
2010
2027
|
and full_graph.in_degree[right] >= 2
|
|
2011
2028
|
):
|
|
2012
|
-
|
|
2013
|
-
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
2014
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
2029
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, start_node, left, right):
|
|
2015
2030
|
# c = !c
|
|
2031
|
+
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
2016
2032
|
last_if_jump = self._remove_last_statement_if_jump(start_node)
|
|
2017
2033
|
new_cond_node = ConditionNode(
|
|
2018
2034
|
last_if_jump.ins_addr if last_if_jump is not None else start_node.addr,
|
|
@@ -2044,10 +2060,9 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2044
2060
|
or (full_graph.in_degree[right] == 1 and not left_succs)
|
|
2045
2061
|
)
|
|
2046
2062
|
):
|
|
2047
|
-
|
|
2048
|
-
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
2049
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
2063
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, start_node, left, right):
|
|
2050
2064
|
# c = !c
|
|
2065
|
+
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
2051
2066
|
try:
|
|
2052
2067
|
last_stmt = self.cond_proc.get_last_statement(start_node)
|
|
2053
2068
|
except EmptyBlockNotice:
|
|
@@ -2169,25 +2184,39 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2169
2184
|
#
|
|
2170
2185
|
# We reduce it into if (cond && next_cond) { body } else { else }
|
|
2171
2186
|
|
|
2187
|
+
# fast-path check to reject nodes that definitely do not work
|
|
2188
|
+
if full_graph.out_degree[start_node] != 2:
|
|
2189
|
+
return False
|
|
2190
|
+
next_cond_candidates = list(full_graph.successors(start_node))
|
|
2191
|
+
check_passed = False
|
|
2192
|
+
for next_cond in next_cond_candidates:
|
|
2193
|
+
if full_graph.out_degree[next_cond] != 2:
|
|
2194
|
+
continue
|
|
2195
|
+
for next_cond_succ in full_graph.successors(next_cond):
|
|
2196
|
+
if full_graph.has_edge(start_node, next_cond_succ):
|
|
2197
|
+
check_passed = True
|
|
2198
|
+
break
|
|
2199
|
+
if check_passed:
|
|
2200
|
+
break
|
|
2201
|
+
if not check_passed:
|
|
2202
|
+
return False
|
|
2203
|
+
|
|
2172
2204
|
r = self._match_acyclic_short_circuit_conditions_type_a(graph, full_graph, start_node)
|
|
2173
2205
|
|
|
2174
2206
|
if r is not None:
|
|
2175
2207
|
left, left_cond, right, left_right_cond, succ = r
|
|
2176
2208
|
# create the condition node
|
|
2177
|
-
|
|
2209
|
+
left_cond_expr = self.cond_proc.convert_claripy_bool_ast(left_cond)
|
|
2210
|
+
left_cond_expr_neg = UnaryOp(None, "Not", left_cond_expr, ins_addr=start_node.addr)
|
|
2211
|
+
left_right_cond_expr = self.cond_proc.convert_claripy_bool_ast(left_right_cond)
|
|
2178
2212
|
if not self._is_single_statement_block(left):
|
|
2179
2213
|
if not self._should_use_multistmtexprs(left):
|
|
2180
2214
|
return False
|
|
2181
2215
|
# create a MultiStatementExpression for left_right_cond
|
|
2182
2216
|
stmts = self._build_multistatementexpr_statements(left)
|
|
2183
2217
|
assert stmts is not None
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
)
|
|
2187
|
-
memo[left_right_cond._hash] = mstmt_expr
|
|
2188
|
-
cond = self.cond_proc.convert_claripy_bool_ast(
|
|
2189
|
-
claripy.Or(claripy.Not(left_cond), left_right_cond), memo=memo
|
|
2190
|
-
)
|
|
2218
|
+
left_right_cond_expr = MultiStatementExpression(None, stmts, left_right_cond_expr, ins_addr=left.addr)
|
|
2219
|
+
cond = BinaryOp(None, "LogicalOr", [left_cond_expr_neg, left_right_cond_expr], ins_addr=start_node.addr)
|
|
2191
2220
|
cond_jump = ConditionalJump(
|
|
2192
2221
|
None,
|
|
2193
2222
|
cond,
|
|
@@ -2212,18 +2241,16 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2212
2241
|
if r is not None:
|
|
2213
2242
|
left, left_cond, right, right_left_cond, else_node = r
|
|
2214
2243
|
# create the condition node
|
|
2215
|
-
|
|
2244
|
+
left_cond_expr = self.cond_proc.convert_claripy_bool_ast(left_cond)
|
|
2245
|
+
right_left_cond_expr = self.cond_proc.convert_claripy_bool_ast(right_left_cond)
|
|
2216
2246
|
if not self._is_single_statement_block(right):
|
|
2217
2247
|
if not self._should_use_multistmtexprs(right):
|
|
2218
2248
|
return False
|
|
2219
2249
|
# create a MultiStatementExpression for left_right_cond
|
|
2220
2250
|
stmts = self._build_multistatementexpr_statements(right)
|
|
2221
2251
|
assert stmts is not None
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
)
|
|
2225
|
-
memo[right_left_cond._hash] = mstmt_expr
|
|
2226
|
-
cond = self.cond_proc.convert_claripy_bool_ast(claripy.Or(left_cond, right_left_cond), memo=memo)
|
|
2252
|
+
right_left_cond_expr = MultiStatementExpression(None, stmts, right_left_cond_expr, ins_addr=left.addr)
|
|
2253
|
+
cond = BinaryOp(None, "LogicalOr", [left_cond_expr, right_left_cond_expr], ins_addr=start_node.addr)
|
|
2227
2254
|
cond_jump = ConditionalJump(
|
|
2228
2255
|
None,
|
|
2229
2256
|
cond,
|
|
@@ -2248,20 +2275,17 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2248
2275
|
if r is not None:
|
|
2249
2276
|
left, left_cond, succ, left_succ_cond, right = r
|
|
2250
2277
|
# create the condition node
|
|
2251
|
-
|
|
2278
|
+
left_cond_expr = self.cond_proc.convert_claripy_bool_ast(left_cond)
|
|
2279
|
+
left_succ_cond_expr = self.cond_proc.convert_claripy_bool_ast(left_succ_cond)
|
|
2252
2280
|
if not self._is_single_statement_block(left):
|
|
2253
2281
|
if not self._should_use_multistmtexprs(left):
|
|
2254
2282
|
return False
|
|
2255
2283
|
# create a MultiStatementExpression for left_right_cond
|
|
2256
2284
|
stmts = self._build_multistatementexpr_statements(left)
|
|
2257
2285
|
assert stmts is not None
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
memo[left_succ_cond._hash] = mstmt_expr
|
|
2262
|
-
cond = self.cond_proc.convert_claripy_bool_ast(
|
|
2263
|
-
claripy.And(left_cond, claripy.Not(left_succ_cond)), memo=memo
|
|
2264
|
-
)
|
|
2286
|
+
left_succ_cond_expr = MultiStatementExpression(None, stmts, left_succ_cond_expr, ins_addr=left.addr)
|
|
2287
|
+
left_succ_cond_expr_neg = UnaryOp(None, "Not", left_succ_cond_expr, ins_addr=start_node.addr)
|
|
2288
|
+
cond = BinaryOp(None, "LogicalAnd", [left_cond_expr, left_succ_cond_expr_neg], ins_addr=start_node.addr)
|
|
2265
2289
|
cond_jump = ConditionalJump(
|
|
2266
2290
|
None,
|
|
2267
2291
|
cond,
|
|
@@ -2285,21 +2309,16 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2285
2309
|
if r is not None:
|
|
2286
2310
|
left, left_cond, right, right_left_cond, else_node = r
|
|
2287
2311
|
# create the condition node
|
|
2288
|
-
|
|
2312
|
+
left_cond_expr = self.cond_proc.convert_claripy_bool_ast(left_cond)
|
|
2313
|
+
left_right_cond_expr = self.cond_proc.convert_claripy_bool_ast(right_left_cond)
|
|
2289
2314
|
if not self._is_single_statement_block(left):
|
|
2290
2315
|
if not self._should_use_multistmtexprs(left):
|
|
2291
2316
|
return False
|
|
2292
2317
|
# create a MultiStatementExpression for left_right_cond
|
|
2293
2318
|
stmts = self._build_multistatementexpr_statements(left)
|
|
2294
2319
|
assert stmts is not None
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
)
|
|
2298
|
-
memo[right_left_cond._hash] = mstmt_expr
|
|
2299
|
-
cond = self.cond_proc.convert_claripy_bool_ast(
|
|
2300
|
-
claripy.And(left_cond, right_left_cond),
|
|
2301
|
-
memo=memo,
|
|
2302
|
-
)
|
|
2320
|
+
left_right_cond_expr = MultiStatementExpression(None, stmts, left_right_cond_expr, ins_addr=left.addr)
|
|
2321
|
+
cond = BinaryOp(None, "LogicalAnd", [left_cond_expr, left_right_cond_expr], ins_addr=start_node.addr)
|
|
2303
2322
|
cond_jump = ConditionalJump(
|
|
2304
2323
|
None,
|
|
2305
2324
|
cond,
|
|
@@ -2349,21 +2368,17 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2349
2368
|
and full_graph.in_degree[left] == 1
|
|
2350
2369
|
and full_graph.in_degree[right] >= 1
|
|
2351
2370
|
):
|
|
2352
|
-
|
|
2353
|
-
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
2354
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
2371
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, start_node, left, right):
|
|
2355
2372
|
# c0 = !c0
|
|
2356
2373
|
left_succs = list(full_graph.successors(left))
|
|
2357
2374
|
if len(left_succs) == 2 and right in left_succs:
|
|
2358
2375
|
other_succ = next(iter(succ for succ in left_succs if succ is not right))
|
|
2359
2376
|
if full_graph.out_degree[right] == 1 and full_graph.has_edge(right, other_succ):
|
|
2360
2377
|
# there must be an edge between right and other_succ
|
|
2361
|
-
|
|
2362
|
-
edge_cond_left_other = self.cond_proc.recover_edge_condition(full_graph, left, other_succ)
|
|
2363
|
-
if claripy.is_true(
|
|
2364
|
-
claripy.Not(edge_cond_left_right) == edge_cond_left_other # type: ignore
|
|
2365
|
-
):
|
|
2378
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, left, right, other_succ):
|
|
2366
2379
|
# c1 = !c1
|
|
2380
|
+
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
2381
|
+
edge_cond_left_right = self.cond_proc.recover_edge_condition(full_graph, left, right)
|
|
2367
2382
|
return left, edge_cond_left, right, edge_cond_left_right, other_succ
|
|
2368
2383
|
return None
|
|
2369
2384
|
|
|
@@ -2386,7 +2401,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2386
2401
|
if len(succs) == 2:
|
|
2387
2402
|
left, right = succs
|
|
2388
2403
|
|
|
2389
|
-
if full_graph.in_degree[left] == 1 and full_graph.in_degree[right]
|
|
2404
|
+
if full_graph.in_degree[left] == 1 and full_graph.in_degree[right] >= 2:
|
|
2390
2405
|
left, right = right, left
|
|
2391
2406
|
|
|
2392
2407
|
# ensure left and right nodes are not the head of a switch-case construct
|
|
@@ -2397,24 +2412,20 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2397
2412
|
|
|
2398
2413
|
if (
|
|
2399
2414
|
self._is_sequential_statement_block(right)
|
|
2400
|
-
and full_graph.in_degree[left]
|
|
2415
|
+
and full_graph.in_degree[left] >= 2
|
|
2401
2416
|
and full_graph.in_degree[right] == 1
|
|
2402
2417
|
):
|
|
2403
|
-
|
|
2404
|
-
edge_cond_right = self.cond_proc.recover_edge_condition(full_graph, start_node, right)
|
|
2405
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_right): # type: ignore
|
|
2418
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, start_node, left, right):
|
|
2406
2419
|
# c0 = !c0
|
|
2407
2420
|
right_succs = list(full_graph.successors(right))
|
|
2408
2421
|
left_succs = list(full_graph.successors(left))
|
|
2409
2422
|
if len(right_succs) == 2 and left in right_succs:
|
|
2410
2423
|
else_node = next(iter(succ for succ in right_succs if succ is not left))
|
|
2411
2424
|
if len([succ for succ in left_succs if succ is not else_node]) == 1:
|
|
2412
|
-
|
|
2413
|
-
edge_cond_right_else = self.cond_proc.recover_edge_condition(full_graph, right, else_node)
|
|
2414
|
-
if claripy.is_true(
|
|
2415
|
-
claripy.Not(edge_cond_right_left) == edge_cond_right_else # type: ignore
|
|
2416
|
-
):
|
|
2425
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, right, left, else_node):
|
|
2417
2426
|
# c1 = !c1
|
|
2427
|
+
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
2428
|
+
edge_cond_right_left = self.cond_proc.recover_edge_condition(full_graph, right, left)
|
|
2418
2429
|
return left, edge_cond_left, right, edge_cond_right_left, else_node
|
|
2419
2430
|
return None
|
|
2420
2431
|
|
|
@@ -2445,23 +2456,19 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2445
2456
|
and full_graph.in_degree[left] == 1
|
|
2446
2457
|
and full_graph.in_degree[successor] >= 1
|
|
2447
2458
|
):
|
|
2448
|
-
|
|
2449
|
-
edge_cond_successor = self.cond_proc.recover_edge_condition(full_graph, start_node, successor)
|
|
2450
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_successor): # type: ignore
|
|
2459
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, start_node, left, successor):
|
|
2451
2460
|
# c0 = !c0
|
|
2452
2461
|
left_succs = list(full_graph.successors(left))
|
|
2453
2462
|
if len(left_succs) == 2 and successor in left_succs:
|
|
2454
2463
|
right = next(iter(succ for succ in left_succs if succ is not successor))
|
|
2455
2464
|
if full_graph.out_degree[right] == 1 and full_graph.has_edge(right, successor):
|
|
2456
2465
|
# there must be an edge from right to successor
|
|
2457
|
-
|
|
2458
|
-
edge_cond_left_successor = self.cond_proc.recover_edge_condition(
|
|
2459
|
-
full_graph, left, successor
|
|
2460
|
-
)
|
|
2461
|
-
if claripy.is_true(
|
|
2462
|
-
claripy.Not(edge_cond_left_right) == edge_cond_left_successor # type: ignore
|
|
2463
|
-
):
|
|
2466
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, left, right, successor):
|
|
2464
2467
|
# c1 = !c1
|
|
2468
|
+
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
2469
|
+
edge_cond_left_successor = self.cond_proc.recover_edge_condition(
|
|
2470
|
+
full_graph, left, successor
|
|
2471
|
+
)
|
|
2465
2472
|
return left, edge_cond_left, successor, edge_cond_left_successor, right
|
|
2466
2473
|
return None
|
|
2467
2474
|
|
|
@@ -2497,17 +2504,15 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2497
2504
|
and full_graph.in_degree[left] == 1
|
|
2498
2505
|
and full_graph.in_degree[else_node] >= 1
|
|
2499
2506
|
):
|
|
2500
|
-
|
|
2501
|
-
edge_cond_else = self.cond_proc.recover_edge_condition(full_graph, start_node, else_node)
|
|
2502
|
-
if claripy.is_true(claripy.Not(edge_cond_left) == edge_cond_else): # type: ignore
|
|
2507
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, start_node, left, else_node):
|
|
2503
2508
|
# c0 = !c0
|
|
2504
2509
|
left_succs = list(full_graph.successors(left))
|
|
2505
2510
|
if len(left_succs) == 2 and else_node in left_succs:
|
|
2506
2511
|
right = next(iter(succ for succ in left_succs if succ is not else_node))
|
|
2507
|
-
|
|
2508
|
-
edge_cond_left_else = self.cond_proc.recover_edge_condition(full_graph, left, else_node)
|
|
2509
|
-
if claripy.is_true(claripy.Not(edge_cond_left_right) == edge_cond_left_else): # type: ignore
|
|
2512
|
+
if self.cond_proc.have_opposite_edge_conditions(full_graph, left, right, else_node):
|
|
2510
2513
|
# c1 = !c1
|
|
2514
|
+
edge_cond_left = self.cond_proc.recover_edge_condition(full_graph, start_node, left)
|
|
2515
|
+
edge_cond_left_right = self.cond_proc.recover_edge_condition(full_graph, left, right)
|
|
2511
2516
|
return left, edge_cond_left, right, edge_cond_left_right, else_node
|
|
2512
2517
|
return None
|
|
2513
2518
|
|
|
@@ -2529,7 +2534,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2529
2534
|
if networkx.is_directed_acyclic_graph(full_graph):
|
|
2530
2535
|
acyclic_graph = full_graph
|
|
2531
2536
|
else:
|
|
2532
|
-
acyclic_graph = to_acyclic_graph(full_graph,
|
|
2537
|
+
acyclic_graph = to_acyclic_graph(full_graph, node_order=self._node_order)
|
|
2533
2538
|
for src, dst in acyclic_graph.edges:
|
|
2534
2539
|
if src is dst:
|
|
2535
2540
|
continue
|
|
@@ -2545,7 +2550,20 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2545
2550
|
if (src.addr, dst.addr) not in self.whitelist_edges:
|
|
2546
2551
|
other_edges.append((src, dst))
|
|
2547
2552
|
|
|
2548
|
-
|
|
2553
|
+
# acyclic graph may contain more than one entry node, so we may add a temporary head node to ensure all nodes
|
|
2554
|
+
# are accounted for in node_seq
|
|
2555
|
+
graph_entries = [nn for nn in acyclic_graph if acyclic_graph.in_degree[nn] == 0]
|
|
2556
|
+
postorder_head = head
|
|
2557
|
+
if len(graph_entries) > 1:
|
|
2558
|
+
postorder_head = Block(0, 0)
|
|
2559
|
+
for nn in graph_entries:
|
|
2560
|
+
acyclic_graph.add_edge(postorder_head, nn)
|
|
2561
|
+
ordered_nodes = list(
|
|
2562
|
+
reversed(list(GraphUtils.dfs_postorder_nodes_deterministic(acyclic_graph, postorder_head)))
|
|
2563
|
+
)
|
|
2564
|
+
if len(graph_entries) > 1:
|
|
2565
|
+
ordered_nodes.remove(postorder_head)
|
|
2566
|
+
acyclic_graph.remove_node(postorder_head)
|
|
2549
2567
|
node_seq = {nn: (len(ordered_nodes) - idx) for (idx, nn) in enumerate(ordered_nodes)} # post-order
|
|
2550
2568
|
|
|
2551
2569
|
if all_edges_wo_dominance:
|
|
@@ -2625,6 +2643,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2625
2643
|
self.virtualized_edges.add((src, dst))
|
|
2626
2644
|
if new_src is not None:
|
|
2627
2645
|
self.replace_nodes(graph, src, new_src)
|
|
2646
|
+
if self._node_order is not None:
|
|
2647
|
+
self._node_order[new_src] = self._node_order[src]
|
|
2628
2648
|
if full_graph is not None:
|
|
2629
2649
|
self.virtualized_edges.add((src, dst))
|
|
2630
2650
|
full_graph.remove_edge(src, dst)
|
|
@@ -2934,10 +2954,29 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2934
2954
|
src, dst = edge_
|
|
2935
2955
|
dst_in_degree = graph.in_degree[dst]
|
|
2936
2956
|
src_out_degree = graph.out_degree[src]
|
|
2937
|
-
return -node_seq
|
|
2957
|
+
return -node_seq[dst], dst_in_degree, src_out_degree, -src.addr, -dst.addr # type: ignore
|
|
2938
2958
|
|
|
2939
2959
|
return sorted(edges, key=_sort_edge, reverse=True)
|
|
2940
2960
|
|
|
2961
|
+
def _generate_node_order(self):
|
|
2962
|
+
the_graph = (
|
|
2963
|
+
self._region.graph_with_successors if self._region.graph_with_successors is not None else self._region.graph
|
|
2964
|
+
)
|
|
2965
|
+
the_head = self._region.head
|
|
2966
|
+
ordered_nodes = GraphUtils.quasi_topological_sort_nodes(
|
|
2967
|
+
the_graph,
|
|
2968
|
+
loop_heads=[the_head],
|
|
2969
|
+
)
|
|
2970
|
+
self._node_order = {n: i for i, n in enumerate(ordered_nodes)}
|
|
2971
|
+
|
|
2972
|
+
def replace_nodes(self, graph, old_node_0, new_node, old_node_1=None, self_loop=True):
|
|
2973
|
+
super().replace_nodes(graph, old_node_0, new_node, old_node_1=old_node_1, self_loop=self_loop)
|
|
2974
|
+
if self._node_order is not None and graph is self._region.graph_with_successors:
|
|
2975
|
+
if old_node_1 is not None:
|
|
2976
|
+
self._node_order[new_node] = min(self._node_order[old_node_0], self._node_order[old_node_1])
|
|
2977
|
+
else:
|
|
2978
|
+
self._node_order[new_node] = self._node_order[old_node_0]
|
|
2979
|
+
|
|
2941
2980
|
@staticmethod
|
|
2942
2981
|
def _replace_node_in_edge_list(edge_list: list[tuple], old_node, new_node) -> None:
|
|
2943
2982
|
for idx in range(len(edge_list)): # pylint:disable=consider-using-enumerate
|
|
@@ -43,7 +43,7 @@ class RecursiveStructurer(Analysis):
|
|
|
43
43
|
self.structurer_cls = structurer_cls if structurer_cls is not None else DreamStructurer
|
|
44
44
|
self.structurer_options = kwargs
|
|
45
45
|
|
|
46
|
-
self.result = None
|
|
46
|
+
self.result: BaseNode | None = None
|
|
47
47
|
self.result_incomplete: bool = False
|
|
48
48
|
|
|
49
49
|
self._analyze()
|
|
@@ -161,6 +161,7 @@ class RecursiveStructurer(Analysis):
|
|
|
161
161
|
for jump_table_head_addr, jumptable in jump_tables.items():
|
|
162
162
|
if jump_table_head_addr not in func_block_addrs:
|
|
163
163
|
continue
|
|
164
|
+
assert jumptable.jumptable_entries is not None
|
|
164
165
|
for entry_addr in jumptable.jumptable_entries:
|
|
165
166
|
entries[entry_addr] = jump_table_head_addr
|
|
166
167
|
|
|
@@ -178,7 +179,7 @@ class RecursiveStructurer(Analysis):
|
|
|
178
179
|
continue
|
|
179
180
|
if node.addr == self.function.addr:
|
|
180
181
|
return node
|
|
181
|
-
if min_node is None or min_node.addr < node.addr:
|
|
182
|
+
if min_node is None or (min_node.addr is not None and node.addr is not None and min_node.addr < node.addr):
|
|
182
183
|
min_node = node
|
|
183
184
|
|
|
184
185
|
return min_node
|