angr 9.2.152__py3-none-macosx_11_0_arm64.whl → 9.2.153__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/cfg/cfg_base.py +1 -1
- angr/analyses/cfg/cfg_fast.py +39 -0
- angr/analyses/decompiler/ail_simplifier.py +0 -1
- angr/analyses/decompiler/clinic.py +45 -1
- angr/analyses/decompiler/region_identifier.py +171 -119
- angr/analyses/smc.py +3 -1
- angr/analyses/typehoon/simple_solver.py +143 -81
- angr/analyses/typehoon/typehoon.py +2 -1
- angr/knowledge_plugins/functions/function.py +10 -4
- angr/lib/angr_native.dylib +0 -0
- {angr-9.2.152.dist-info → angr-9.2.153.dist-info}/METADATA +6 -6
- {angr-9.2.152.dist-info → angr-9.2.153.dist-info}/RECORD +17 -17
- {angr-9.2.152.dist-info → angr-9.2.153.dist-info}/WHEEL +1 -1
- {angr-9.2.152.dist-info → angr-9.2.153.dist-info}/entry_points.txt +0 -0
- {angr-9.2.152.dist-info → angr-9.2.153.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.152.dist-info → angr-9.2.153.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
angr/analyses/cfg/cfg_base.py
CHANGED
|
@@ -1515,7 +1515,7 @@ class CFGBase(Analysis):
|
|
|
1515
1515
|
Revisit the entire control flow graph, create Function instances accordingly, and correctly put blocks into
|
|
1516
1516
|
each function.
|
|
1517
1517
|
|
|
1518
|
-
Although Function objects are
|
|
1518
|
+
Although Function objects are created during the CFG recovery, they are neither sound nor accurate. With a
|
|
1519
1519
|
pre-constructed CFG, this method rebuilds all functions bearing the following rules:
|
|
1520
1520
|
|
|
1521
1521
|
- A block may only belong to one function.
|
angr/analyses/cfg/cfg_fast.py
CHANGED
|
@@ -1554,6 +1554,45 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1554
1554
|
}:
|
|
1555
1555
|
func.info["is_alloca_probe"] = True
|
|
1556
1556
|
|
|
1557
|
+
# determine if the function is _guard_xfg_dispatch_icall_nop or _guard_xfg_dispatch_icall_fptr
|
|
1558
|
+
if func is not None and not func.is_simprocedure and len(func.block_addrs_set) in {1, 2}:
|
|
1559
|
+
# _guard_xfg_dispatch_icall_nop jumps to _guard_xfg_dispatch_icall_fptr, but we may or may not identify
|
|
1560
|
+
# _guard_xfg_dispatch_icall_fptr as a separate function.
|
|
1561
|
+
# so, two possibilities:
|
|
1562
|
+
# - _guard_xfg_dispatch_icall_nop is a function with one block and jumps to
|
|
1563
|
+
# _guard_xfg_dispatch_icall_fptr.
|
|
1564
|
+
# - _guard_xfg_dispatch_icall_nop is a function with 2 blocks, and the second block is the body of
|
|
1565
|
+
# _guard_xfg_dispatch_icall_fptr.
|
|
1566
|
+
try:
|
|
1567
|
+
block = func.get_block(func.addr)
|
|
1568
|
+
except SimTranslationError:
|
|
1569
|
+
block = None
|
|
1570
|
+
if block is not None and block.instructions == 1:
|
|
1571
|
+
insn = block.capstone.insns[0]
|
|
1572
|
+
if block.bytes == b"\xff\xe0":
|
|
1573
|
+
func.info["jmp_rax"] = True
|
|
1574
|
+
elif (
|
|
1575
|
+
insn.mnemonic == "jmp"
|
|
1576
|
+
and insn.operands[0].type == capstone.x86.X86_OP_MEM
|
|
1577
|
+
and insn.operands[0].mem.base == capstone.x86.X86_REG_RIP
|
|
1578
|
+
and insn.operands[0].mem.disp > 0
|
|
1579
|
+
and insn.operands[0].mem.index == 0
|
|
1580
|
+
):
|
|
1581
|
+
# where is it jumping to?
|
|
1582
|
+
jumpout_targets = list(self.graph.successors(self.model.get_any_node(func.addr)))
|
|
1583
|
+
if len(jumpout_targets) == 1:
|
|
1584
|
+
jumpout_target = jumpout_targets[0].addr
|
|
1585
|
+
if len(func.block_addrs_set) == 1 and len(func.jumpout_sites) == 1:
|
|
1586
|
+
if (
|
|
1587
|
+
self.kb.functions.contains_addr(jumpout_target)
|
|
1588
|
+
and self.kb.functions.get_by_addr(jumpout_target).get_block(jumpout_target).bytes
|
|
1589
|
+
== b"\xff\xe0"
|
|
1590
|
+
):
|
|
1591
|
+
func.info["jmp_rax"] = True
|
|
1592
|
+
elif len(func.block_addrs_set) == 2 and func.get_block(jumpout_target).bytes == b"\xff\xe0":
|
|
1593
|
+
# check the second block and ensure it's jmp rax
|
|
1594
|
+
func.info["jmp_rax"] = True
|
|
1595
|
+
|
|
1557
1596
|
elif self.project.arch.name == "X86":
|
|
1558
1597
|
# determine if the function is __alloca_probe
|
|
1559
1598
|
func = self.kb.functions.get_by_addr(func_addr) if self.kb.functions.contains_addr(func_addr) else None
|
|
@@ -203,7 +203,6 @@ class AILSimplifier(Analysis):
|
|
|
203
203
|
AILGraphWalker(self.func_graph, _handler, replace_nodes=True).walk()
|
|
204
204
|
self.blocks = {}
|
|
205
205
|
|
|
206
|
-
@timethis
|
|
207
206
|
def _compute_reaching_definitions(self) -> SRDAModel:
|
|
208
207
|
# Computing reaching definitions or return the cached one
|
|
209
208
|
if self._reaching_definitions is not None:
|
|
@@ -485,6 +485,8 @@ class Clinic(Analysis):
|
|
|
485
485
|
|
|
486
486
|
# duplicate orphaned conditional jump blocks
|
|
487
487
|
ail_graph = self._duplicate_orphaned_cond_jumps(ail_graph)
|
|
488
|
+
# rewrite jmp_rax function calls
|
|
489
|
+
ail_graph = self._rewrite_jump_rax_calls(ail_graph)
|
|
488
490
|
|
|
489
491
|
# Transform the graph into partial SSA form
|
|
490
492
|
self._update_progress(35.0, text="Transforming to partial-SSA form")
|
|
@@ -930,7 +932,7 @@ class Clinic(Analysis):
|
|
|
930
932
|
self.kb.callsite_prototypes.set_prototype(callsite.addr, cc.cc, cc.prototype, manual=False)
|
|
931
933
|
if func_graph is not None and cc.prototype.returnty is not None:
|
|
932
934
|
# patch the AIL call statement if we can find one
|
|
933
|
-
callsite_ail_block: ailment.Block = next(
|
|
935
|
+
callsite_ail_block: ailment.Block | None = next(
|
|
934
936
|
iter(bb for bb in func_graph if bb.addr == callsite.addr), None
|
|
935
937
|
)
|
|
936
938
|
if callsite_ail_block is not None and callsite_ail_block.statements:
|
|
@@ -1005,6 +1007,7 @@ class Clinic(Analysis):
|
|
|
1005
1007
|
:return: None
|
|
1006
1008
|
"""
|
|
1007
1009
|
assert self._func_graph is not None
|
|
1010
|
+
assert self._blocks_by_addr_and_size is not None
|
|
1008
1011
|
|
|
1009
1012
|
for block_node in self._func_graph.nodes():
|
|
1010
1013
|
ail_block = self._convert(block_node)
|
|
@@ -2178,6 +2181,47 @@ class Clinic(Analysis):
|
|
|
2178
2181
|
|
|
2179
2182
|
return ail_graph
|
|
2180
2183
|
|
|
2184
|
+
def _rewrite_jump_rax_calls(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
|
|
2185
|
+
"""
|
|
2186
|
+
Rewrite calls to special functions (e.g., guard_dispatch_icall_nop) into `call rax`.
|
|
2187
|
+
"""
|
|
2188
|
+
|
|
2189
|
+
if self.project.arch.name != "AMD64":
|
|
2190
|
+
return ail_graph
|
|
2191
|
+
if self._cfg is None:
|
|
2192
|
+
return ail_graph
|
|
2193
|
+
|
|
2194
|
+
for block in ail_graph:
|
|
2195
|
+
if not block.statements:
|
|
2196
|
+
continue
|
|
2197
|
+
assert block.addr is not None
|
|
2198
|
+
last_stmt = block.statements[-1]
|
|
2199
|
+
if isinstance(last_stmt, ailment.Stmt.Call):
|
|
2200
|
+
# we can't examine the call target at this point because constant propagation hasn't run yet; we consult
|
|
2201
|
+
# the CFG instead
|
|
2202
|
+
callsite_node = self._cfg.get_any_node(block.addr, anyaddr=True)
|
|
2203
|
+
if callsite_node is None:
|
|
2204
|
+
break
|
|
2205
|
+
callees = self._cfg.get_successors(callsite_node, jumpkind="Ijk_Call")
|
|
2206
|
+
if len(callees) != 1:
|
|
2207
|
+
break
|
|
2208
|
+
callee = callees[0].addr
|
|
2209
|
+
if self.kb.functions.contains_addr(callee):
|
|
2210
|
+
callee_func = self.kb.functions.get_by_addr(callee)
|
|
2211
|
+
if callee_func.info.get("jmp_rax", False) is True:
|
|
2212
|
+
# rewrite this statement into Call(rax)
|
|
2213
|
+
call_stmt = last_stmt.copy()
|
|
2214
|
+
call_stmt.target = ailment.Expr.Register(
|
|
2215
|
+
self._ail_manager.next_atom(),
|
|
2216
|
+
None,
|
|
2217
|
+
self.project.arch.registers["rax"][0],
|
|
2218
|
+
64,
|
|
2219
|
+
ins_addr=call_stmt.ins_addr,
|
|
2220
|
+
)
|
|
2221
|
+
block.statements[-1] = call_stmt
|
|
2222
|
+
|
|
2223
|
+
return ail_graph
|
|
2224
|
+
|
|
2181
2225
|
def _rewrite_ite_expressions(self, ail_graph):
|
|
2182
2226
|
cfg = self._cfg
|
|
2183
2227
|
for block in list(ail_graph):
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
from typing import Any
|
|
2
3
|
from itertools import count
|
|
3
4
|
from collections import defaultdict
|
|
4
5
|
import logging
|
|
@@ -70,6 +71,9 @@ class RegionIdentifier(Analysis):
|
|
|
70
71
|
self._largest_successor_tree_outside_loop = largest_successor_tree_outside_loop
|
|
71
72
|
self._force_loop_single_exit = force_loop_single_exit
|
|
72
73
|
self._complete_successors = complete_successors
|
|
74
|
+
# we keep a dictionary of node and their traversal order in a quasi-topological traversal and update this
|
|
75
|
+
# dictionary as we update the graph
|
|
76
|
+
self._node_order: dict[Any, tuple[int, int]] = {}
|
|
73
77
|
|
|
74
78
|
self._analyze()
|
|
75
79
|
|
|
@@ -102,11 +106,30 @@ class RegionIdentifier(Analysis):
|
|
|
102
106
|
|
|
103
107
|
self._start_node = self._get_start_node(graph)
|
|
104
108
|
|
|
109
|
+
self._node_order = self._compute_node_order(graph)
|
|
110
|
+
|
|
105
111
|
self.region = self._make_regions(graph)
|
|
106
112
|
|
|
107
113
|
# make regions into block address lists
|
|
108
114
|
self.regions_by_block_addrs = self._make_regions_by_block_addrs()
|
|
109
115
|
|
|
116
|
+
@staticmethod
|
|
117
|
+
def _compute_node_order(graph: networkx.DiGraph) -> dict[Any, tuple[int, int]]:
|
|
118
|
+
sorted_nodes = GraphUtils.quasi_topological_sort_nodes(graph)
|
|
119
|
+
node_order = {}
|
|
120
|
+
for i, n in enumerate(sorted_nodes):
|
|
121
|
+
node_order[n] = i, 0
|
|
122
|
+
return node_order
|
|
123
|
+
|
|
124
|
+
def _sort_nodes(self, nodes: list | set) -> list:
|
|
125
|
+
"""
|
|
126
|
+
Sorts the nodes in the order specified in self._node_order.
|
|
127
|
+
|
|
128
|
+
:param nodes: A list or set of nodes to be sorted.
|
|
129
|
+
:return: A sorted list of nodes.
|
|
130
|
+
"""
|
|
131
|
+
return sorted(nodes, key=lambda n: self._node_order[n])
|
|
132
|
+
|
|
110
133
|
def _make_regions_by_block_addrs(self) -> list[list[tuple[int, int | None]]]:
|
|
111
134
|
"""
|
|
112
135
|
Creates a list of addr lists representing each region without recursion. A single region is defined
|
|
@@ -182,30 +205,6 @@ class RegionIdentifier(Analysis):
|
|
|
182
205
|
None,
|
|
183
206
|
)
|
|
184
207
|
|
|
185
|
-
def _test_reducibility(self):
|
|
186
|
-
# make a copy of the graph
|
|
187
|
-
graph = networkx.DiGraph(self._graph)
|
|
188
|
-
|
|
189
|
-
# preprocess: make it a super graph
|
|
190
|
-
self._make_supergraph(graph)
|
|
191
|
-
|
|
192
|
-
while True:
|
|
193
|
-
changed = False
|
|
194
|
-
|
|
195
|
-
# find a node with a back-edge, remove the edge (deleting the loop), and replace it with a MultiNode
|
|
196
|
-
changed |= self._remove_self_loop(graph)
|
|
197
|
-
|
|
198
|
-
# find a node that has only one predecessor, and merge it with its predecessor (replace them with a
|
|
199
|
-
# MultiNode)
|
|
200
|
-
changed |= self._merge_single_entry_node(graph)
|
|
201
|
-
|
|
202
|
-
if not changed:
|
|
203
|
-
# a fixed-point is reached
|
|
204
|
-
break
|
|
205
|
-
|
|
206
|
-
# Flow graph reducibility, Hecht and Ullman
|
|
207
|
-
return len(graph.nodes) == 1
|
|
208
|
-
|
|
209
208
|
def _make_supergraph(self, graph: networkx.DiGraph):
|
|
210
209
|
|
|
211
210
|
entry_node = None
|
|
@@ -236,7 +235,7 @@ class RegionIdentifier(Analysis):
|
|
|
236
235
|
|
|
237
236
|
def _find_loop_headers(self, graph: networkx.DiGraph) -> list:
|
|
238
237
|
heads = list({t for _, t in dfs_back_edges(graph, self._start_node)})
|
|
239
|
-
return
|
|
238
|
+
return self._sort_nodes(heads)
|
|
240
239
|
|
|
241
240
|
def _find_initial_loop_nodes(self, graph: networkx.DiGraph, head):
|
|
242
241
|
# TODO optimize
|
|
@@ -290,7 +289,7 @@ class RegionIdentifier(Analysis):
|
|
|
290
289
|
# node.
|
|
291
290
|
subgraph = networkx.DiGraph()
|
|
292
291
|
|
|
293
|
-
sorted_refined_exit_nodes =
|
|
292
|
+
sorted_refined_exit_nodes = self._sort_nodes(refined_exit_nodes)
|
|
294
293
|
while len(sorted_refined_exit_nodes) > 1 and new_exit_nodes:
|
|
295
294
|
# visit each node in refined_exit_nodes once and determine which nodes to consider as loop nodes
|
|
296
295
|
candidate_nodes = {}
|
|
@@ -324,7 +323,7 @@ class RegionIdentifier(Analysis):
|
|
|
324
323
|
|
|
325
324
|
sorted_refined_exit_nodes += list(new_exit_nodes)
|
|
326
325
|
sorted_refined_exit_nodes = list(set(sorted_refined_exit_nodes))
|
|
327
|
-
sorted_refined_exit_nodes =
|
|
326
|
+
sorted_refined_exit_nodes = self._sort_nodes(sorted_refined_exit_nodes)
|
|
328
327
|
|
|
329
328
|
refined_exit_nodes = set(sorted_refined_exit_nodes)
|
|
330
329
|
refined_loop_nodes = refined_loop_nodes - refined_exit_nodes
|
|
@@ -373,37 +372,6 @@ class RegionIdentifier(Analysis):
|
|
|
373
372
|
|
|
374
373
|
return refined_loop_nodes, refined_exit_nodes
|
|
375
374
|
|
|
376
|
-
def _remove_self_loop(self, graph: networkx.DiGraph):
|
|
377
|
-
r = False
|
|
378
|
-
|
|
379
|
-
while True:
|
|
380
|
-
for node in graph.nodes():
|
|
381
|
-
if node in graph[node]:
|
|
382
|
-
# found a self loop
|
|
383
|
-
self._remove_node(graph, node)
|
|
384
|
-
r = True
|
|
385
|
-
break
|
|
386
|
-
else:
|
|
387
|
-
break
|
|
388
|
-
|
|
389
|
-
return r
|
|
390
|
-
|
|
391
|
-
def _merge_single_entry_node(self, graph: networkx.DiGraph):
|
|
392
|
-
r = False
|
|
393
|
-
|
|
394
|
-
while True:
|
|
395
|
-
for node in networkx.dfs_postorder_nodes(graph):
|
|
396
|
-
preds = list(graph.predecessors(node))
|
|
397
|
-
if len(preds) == 1:
|
|
398
|
-
# merge the two nodes
|
|
399
|
-
self._absorb_node(graph, preds[0], node)
|
|
400
|
-
r = True
|
|
401
|
-
break
|
|
402
|
-
else:
|
|
403
|
-
break
|
|
404
|
-
|
|
405
|
-
return r
|
|
406
|
-
|
|
407
375
|
def _make_regions(self, graph: networkx.DiGraph):
|
|
408
376
|
structured_loop_headers = set()
|
|
409
377
|
new_regions = []
|
|
@@ -535,7 +503,14 @@ class RegionIdentifier(Analysis):
|
|
|
535
503
|
abnormal_exit_nodes = set()
|
|
536
504
|
|
|
537
505
|
region = self._abstract_cyclic_region(
|
|
538
|
-
graph,
|
|
506
|
+
graph,
|
|
507
|
+
refined_loop_nodes,
|
|
508
|
+
head,
|
|
509
|
+
normal_entries,
|
|
510
|
+
abnormal_entries,
|
|
511
|
+
normal_exit_node,
|
|
512
|
+
abnormal_exit_nodes,
|
|
513
|
+
self._node_order,
|
|
539
514
|
)
|
|
540
515
|
if region.successors is not None and len(region.successors) > 1 and self._force_loop_single_exit:
|
|
541
516
|
# multi-successor region. refinement is required
|
|
@@ -661,6 +636,10 @@ class RegionIdentifier(Analysis):
|
|
|
661
636
|
graph.remove_edge(region, succ)
|
|
662
637
|
graph.add_edge(cond, succ, **edge_data)
|
|
663
638
|
|
|
639
|
+
# compute the node order of newly created nodes
|
|
640
|
+
self._node_order[region] = region_node_order = min(self._node_order[node_] for node_ in region.graph)
|
|
641
|
+
self._node_order[cond] = region_node_order[0], region_node_order[1] + 1
|
|
642
|
+
|
|
664
643
|
#
|
|
665
644
|
# Acyclic regions
|
|
666
645
|
#
|
|
@@ -733,6 +712,7 @@ class RegionIdentifier(Analysis):
|
|
|
733
712
|
graph,
|
|
734
713
|
GraphRegion(node, subgraph, None, None, False, None, cyclic_ancestor=cyclic),
|
|
735
714
|
[],
|
|
715
|
+
self._node_order,
|
|
736
716
|
secondary_graph=secondary_graph,
|
|
737
717
|
)
|
|
738
718
|
continue
|
|
@@ -780,7 +760,12 @@ class RegionIdentifier(Analysis):
|
|
|
780
760
|
l.debug("Node %r, frontier %r.", node, frontier)
|
|
781
761
|
# l.debug("Identified an acyclic region %s.", self._dbg_block_list(region.graph.nodes()))
|
|
782
762
|
self._abstract_acyclic_region(
|
|
783
|
-
graph,
|
|
763
|
+
graph,
|
|
764
|
+
region,
|
|
765
|
+
frontier,
|
|
766
|
+
self._node_order,
|
|
767
|
+
dummy_endnode=dummy_endnode,
|
|
768
|
+
secondary_graph=secondary_graph,
|
|
784
769
|
)
|
|
785
770
|
# assert dummy_endnode not in graph
|
|
786
771
|
region_created = True
|
|
@@ -909,11 +894,17 @@ class RegionIdentifier(Analysis):
|
|
|
909
894
|
)
|
|
910
895
|
return None
|
|
911
896
|
|
|
897
|
+
@staticmethod
|
|
912
898
|
def _abstract_acyclic_region(
|
|
913
|
-
|
|
899
|
+
graph: networkx.DiGraph,
|
|
900
|
+
region,
|
|
901
|
+
frontier,
|
|
902
|
+
node_order: dict[Any, tuple[int, int]],
|
|
903
|
+
dummy_endnode=None,
|
|
904
|
+
secondary_graph=None,
|
|
914
905
|
):
|
|
915
|
-
in_edges =
|
|
916
|
-
out_edges =
|
|
906
|
+
in_edges = RegionIdentifier._region_in_edges(graph, region, data=True)
|
|
907
|
+
out_edges = RegionIdentifier._region_out_edges(graph, region, data=True)
|
|
917
908
|
|
|
918
909
|
nodes_set = set()
|
|
919
910
|
for node_ in list(region.graph.nodes()):
|
|
@@ -922,6 +913,7 @@ class RegionIdentifier(Analysis):
|
|
|
922
913
|
graph.remove_node(node_)
|
|
923
914
|
|
|
924
915
|
graph.add_node(region)
|
|
916
|
+
node_order[region] = min(node_order[node_] for node_ in nodes_set)
|
|
925
917
|
|
|
926
918
|
for src, _, data in in_edges:
|
|
927
919
|
if src not in nodes_set:
|
|
@@ -937,7 +929,7 @@ class RegionIdentifier(Analysis):
|
|
|
937
929
|
graph.add_edge(region, frontier_node)
|
|
938
930
|
|
|
939
931
|
if secondary_graph is not None:
|
|
940
|
-
|
|
932
|
+
RegionIdentifier._abstract_acyclic_region(secondary_graph, region, {}, node_order)
|
|
941
933
|
|
|
942
934
|
@staticmethod
|
|
943
935
|
def _abstract_cyclic_region(
|
|
@@ -948,6 +940,7 @@ class RegionIdentifier(Analysis):
|
|
|
948
940
|
abnormal_entries,
|
|
949
941
|
normal_exit_node,
|
|
950
942
|
abnormal_exit_nodes,
|
|
943
|
+
node_order: dict[Any, tuple[int, int]],
|
|
951
944
|
):
|
|
952
945
|
region = GraphRegion(head, None, None, None, True, None)
|
|
953
946
|
|
|
@@ -1019,6 +1012,8 @@ class RegionIdentifier(Analysis):
|
|
|
1019
1012
|
graph.add_node(region)
|
|
1020
1013
|
for src, dst, data in delayed_edges:
|
|
1021
1014
|
graph.add_edge(src, dst, **data)
|
|
1015
|
+
# update node order
|
|
1016
|
+
node_order[region] = node_order[head]
|
|
1022
1017
|
|
|
1023
1018
|
region.full_graph = full_graph
|
|
1024
1019
|
|
|
@@ -1039,25 +1034,8 @@ class RegionIdentifier(Analysis):
|
|
|
1039
1034
|
out_edges.append((region, dst, data_))
|
|
1040
1035
|
return out_edges
|
|
1041
1036
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
out_edges = [(src, dst, data) for (src, dst, data) in graph.out_edges(node, data=True) if dst is not node]
|
|
1045
|
-
|
|
1046
|
-
# true case: it forms a region by itself :-)
|
|
1047
|
-
new_node = None if len(in_edges) <= 1 and len(out_edges) <= 1 else MultiNode([node])
|
|
1048
|
-
|
|
1049
|
-
graph.remove_node(node)
|
|
1050
|
-
|
|
1051
|
-
if new_node is not None:
|
|
1052
|
-
for src, _, data in in_edges:
|
|
1053
|
-
graph.add_edge(src, new_node, **data)
|
|
1054
|
-
|
|
1055
|
-
for _, dst, data in out_edges:
|
|
1056
|
-
graph.add_edge(new_node, dst, **data)
|
|
1057
|
-
|
|
1058
|
-
def _merge_nodes(
|
|
1059
|
-
self, graph: networkx.DiGraph, node_a, node_b, force_multinode=False
|
|
1060
|
-
): # pylint:disable=no-self-use
|
|
1037
|
+
@staticmethod
|
|
1038
|
+
def _merge_nodes(graph: networkx.DiGraph, node_a, node_b, force_multinode=False):
|
|
1061
1039
|
in_edges = list(graph.in_edges(node_a, data=True))
|
|
1062
1040
|
out_edges = list(graph.out_edges(node_b, data=True))
|
|
1063
1041
|
|
|
@@ -1089,9 +1067,116 @@ class RegionIdentifier(Analysis):
|
|
|
1089
1067
|
|
|
1090
1068
|
return new_node
|
|
1091
1069
|
|
|
1092
|
-
def
|
|
1093
|
-
|
|
1094
|
-
|
|
1070
|
+
def _ensure_jump_at_loop_exit_ends(self, node: Block | MultiNode) -> None:
|
|
1071
|
+
if isinstance(node, Block):
|
|
1072
|
+
if not node.statements:
|
|
1073
|
+
node.statements.append(
|
|
1074
|
+
Jump(
|
|
1075
|
+
None,
|
|
1076
|
+
Const(None, None, node.addr + node.original_size, self.project.arch.bits),
|
|
1077
|
+
ins_addr=node.addr,
|
|
1078
|
+
)
|
|
1079
|
+
)
|
|
1080
|
+
else:
|
|
1081
|
+
if not isinstance(first_nonlabel_nonphi_statement(node), ConditionalJump) and not isinstance(
|
|
1082
|
+
node.statements[-1],
|
|
1083
|
+
(
|
|
1084
|
+
Jump,
|
|
1085
|
+
ConditionalJump,
|
|
1086
|
+
IncompleteSwitchCaseHeadStatement,
|
|
1087
|
+
),
|
|
1088
|
+
):
|
|
1089
|
+
node.statements.append(
|
|
1090
|
+
Jump(
|
|
1091
|
+
None,
|
|
1092
|
+
Const(None, None, node.addr + node.original_size, self.project.arch.bits),
|
|
1093
|
+
ins_addr=node.addr,
|
|
1094
|
+
)
|
|
1095
|
+
)
|
|
1096
|
+
elif isinstance(node, MultiNode) and node.nodes:
|
|
1097
|
+
self._ensure_jump_at_loop_exit_ends(node.nodes[-1])
|
|
1098
|
+
|
|
1099
|
+
@staticmethod
|
|
1100
|
+
def _dbg_block_list(blocks):
|
|
1101
|
+
return [(hex(b.addr) if hasattr(b, "addr") else repr(b)) for b in blocks]
|
|
1102
|
+
|
|
1103
|
+
#
|
|
1104
|
+
# Reducibility
|
|
1105
|
+
#
|
|
1106
|
+
|
|
1107
|
+
def test_reducibility(self) -> bool:
|
|
1108
|
+
# make a copy of the graph
|
|
1109
|
+
graph = networkx.DiGraph(self._graph)
|
|
1110
|
+
|
|
1111
|
+
# preprocess: make it a super graph
|
|
1112
|
+
self._make_supergraph(graph)
|
|
1113
|
+
|
|
1114
|
+
while True:
|
|
1115
|
+
changed = False
|
|
1116
|
+
|
|
1117
|
+
# find a node with a back-edge, remove the edge (deleting the loop), and replace it with a MultiNode
|
|
1118
|
+
changed |= self._remove_self_loop(graph)
|
|
1119
|
+
|
|
1120
|
+
# find a node that has only one predecessor, and merge it with its predecessor (replace them with a
|
|
1121
|
+
# MultiNode)
|
|
1122
|
+
changed |= self._merge_single_entry_node(graph)
|
|
1123
|
+
|
|
1124
|
+
if not changed:
|
|
1125
|
+
# a fixed-point is reached
|
|
1126
|
+
break
|
|
1127
|
+
|
|
1128
|
+
# Flow graph reducibility, Hecht and Ullman
|
|
1129
|
+
return len(graph.nodes) == 1
|
|
1130
|
+
|
|
1131
|
+
def _remove_self_loop(self, graph: networkx.DiGraph) -> bool:
|
|
1132
|
+
r = False
|
|
1133
|
+
|
|
1134
|
+
while True:
|
|
1135
|
+
for node in graph.nodes():
|
|
1136
|
+
if node in graph[node]:
|
|
1137
|
+
# found a self loop
|
|
1138
|
+
self._remove_node(graph, node)
|
|
1139
|
+
r = True
|
|
1140
|
+
break
|
|
1141
|
+
else:
|
|
1142
|
+
break
|
|
1143
|
+
|
|
1144
|
+
return r
|
|
1145
|
+
|
|
1146
|
+
def _merge_single_entry_node(self, graph: networkx.DiGraph) -> bool:
|
|
1147
|
+
r = False
|
|
1148
|
+
|
|
1149
|
+
while True:
|
|
1150
|
+
for node in networkx.dfs_postorder_nodes(graph):
|
|
1151
|
+
preds = list(graph.predecessors(node))
|
|
1152
|
+
if len(preds) == 1:
|
|
1153
|
+
# merge the two nodes
|
|
1154
|
+
self._absorb_node(graph, preds[0], node)
|
|
1155
|
+
r = True
|
|
1156
|
+
break
|
|
1157
|
+
else:
|
|
1158
|
+
break
|
|
1159
|
+
|
|
1160
|
+
return r
|
|
1161
|
+
|
|
1162
|
+
def _remove_node(self, graph: networkx.DiGraph, node): # pylint:disable=no-self-use
|
|
1163
|
+
in_edges = [(src, dst, data) for (src, dst, data) in graph.in_edges(node, data=True) if src is not node]
|
|
1164
|
+
out_edges = [(src, dst, data) for (src, dst, data) in graph.out_edges(node, data=True) if dst is not node]
|
|
1165
|
+
|
|
1166
|
+
# true case: it forms a region by itself :-)
|
|
1167
|
+
new_node = None if len(in_edges) <= 1 and len(out_edges) <= 1 else MultiNode([node])
|
|
1168
|
+
|
|
1169
|
+
graph.remove_node(node)
|
|
1170
|
+
|
|
1171
|
+
if new_node is not None:
|
|
1172
|
+
for src, _, data in in_edges:
|
|
1173
|
+
graph.add_edge(src, new_node, **data)
|
|
1174
|
+
|
|
1175
|
+
for _, dst, data in out_edges:
|
|
1176
|
+
graph.add_edge(new_node, dst, **data)
|
|
1177
|
+
|
|
1178
|
+
@staticmethod
|
|
1179
|
+
def _absorb_node(graph: networkx.DiGraph, node_mommy, node_kiddie, force_multinode=False):
|
|
1095
1180
|
in_edges_mommy = graph.in_edges(node_mommy, data=True)
|
|
1096
1181
|
out_edges_mommy = graph.out_edges(node_mommy, data=True)
|
|
1097
1182
|
out_edges_kiddie = graph.out_edges(node_kiddie, data=True)
|
|
@@ -1129,38 +1214,5 @@ class RegionIdentifier(Analysis):
|
|
|
1129
1214
|
assert node_mommy not in graph
|
|
1130
1215
|
assert node_kiddie not in graph
|
|
1131
1216
|
|
|
1132
|
-
def _ensure_jump_at_loop_exit_ends(self, node: Block | MultiNode) -> None:
|
|
1133
|
-
if isinstance(node, Block):
|
|
1134
|
-
if not node.statements:
|
|
1135
|
-
node.statements.append(
|
|
1136
|
-
Jump(
|
|
1137
|
-
None,
|
|
1138
|
-
Const(None, None, node.addr + node.original_size, self.project.arch.bits),
|
|
1139
|
-
ins_addr=node.addr,
|
|
1140
|
-
)
|
|
1141
|
-
)
|
|
1142
|
-
else:
|
|
1143
|
-
if not isinstance(first_nonlabel_nonphi_statement(node), ConditionalJump) and not isinstance(
|
|
1144
|
-
node.statements[-1],
|
|
1145
|
-
(
|
|
1146
|
-
Jump,
|
|
1147
|
-
ConditionalJump,
|
|
1148
|
-
IncompleteSwitchCaseHeadStatement,
|
|
1149
|
-
),
|
|
1150
|
-
):
|
|
1151
|
-
node.statements.append(
|
|
1152
|
-
Jump(
|
|
1153
|
-
None,
|
|
1154
|
-
Const(None, None, node.addr + node.original_size, self.project.arch.bits),
|
|
1155
|
-
ins_addr=node.addr,
|
|
1156
|
-
)
|
|
1157
|
-
)
|
|
1158
|
-
elif isinstance(node, MultiNode) and node.nodes:
|
|
1159
|
-
self._ensure_jump_at_loop_exit_ends(node.nodes[-1])
|
|
1160
|
-
|
|
1161
|
-
@staticmethod
|
|
1162
|
-
def _dbg_block_list(blocks):
|
|
1163
|
-
return [(hex(b.addr) if hasattr(b, "addr") else repr(b)) for b in blocks]
|
|
1164
|
-
|
|
1165
1217
|
|
|
1166
1218
|
register_analysis(RegionIdentifier, "RegionIdentifier")
|
angr/analyses/smc.py
CHANGED
|
@@ -42,6 +42,8 @@ class TraceClassifier:
|
|
|
42
42
|
"""
|
|
43
43
|
addr = state.solver.eval(state.inspect.mem_write_address)
|
|
44
44
|
length = state.inspect.mem_write_length
|
|
45
|
+
if length is None:
|
|
46
|
+
length = len(state.inspect.mem_write_expr) // state.arch.byte_width
|
|
45
47
|
if not isinstance(length, int):
|
|
46
48
|
length = state.solver.eval(length)
|
|
47
49
|
self.map.add(addr, length, TraceActions.WRITE)
|
|
@@ -103,7 +105,7 @@ class SelfModifyingCodeAnalysis(Analysis):
|
|
|
103
105
|
"""
|
|
104
106
|
:param subject: Subject of analysis
|
|
105
107
|
:param max_bytes: Maximum number of bytes from subject address. 0 for no limit (default).
|
|
106
|
-
:param state: State to begin executing from
|
|
108
|
+
:param state: State to begin executing from.
|
|
107
109
|
"""
|
|
108
110
|
assert self.project.selfmodifying_code
|
|
109
111
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
import enum
|
|
4
4
|
from collections import defaultdict
|
|
5
|
+
from contextlib import suppress
|
|
5
6
|
import logging
|
|
6
7
|
|
|
7
8
|
import networkx
|
|
@@ -51,23 +52,6 @@ from .dfa import DFAConstraintSolver, EmptyEpsilonNFAError
|
|
|
51
52
|
_l = logging.getLogger(__name__)
|
|
52
53
|
|
|
53
54
|
|
|
54
|
-
PRIMITIVE_TYPES = {
|
|
55
|
-
TopType(),
|
|
56
|
-
Int(),
|
|
57
|
-
Int8(),
|
|
58
|
-
Int16(),
|
|
59
|
-
Int32(),
|
|
60
|
-
Int64(),
|
|
61
|
-
Pointer32(),
|
|
62
|
-
Pointer64(),
|
|
63
|
-
BottomType(),
|
|
64
|
-
Struct(),
|
|
65
|
-
Array(),
|
|
66
|
-
Float(),
|
|
67
|
-
Float32(),
|
|
68
|
-
Float64(),
|
|
69
|
-
}
|
|
70
|
-
|
|
71
55
|
Top_ = TopType()
|
|
72
56
|
Int_ = Int()
|
|
73
57
|
Int64_ = Int64()
|
|
@@ -83,6 +67,25 @@ Float_ = Float()
|
|
|
83
67
|
Float32_ = Float32()
|
|
84
68
|
Float64_ = Float64()
|
|
85
69
|
|
|
70
|
+
|
|
71
|
+
PRIMITIVE_TYPES = {
|
|
72
|
+
Top_,
|
|
73
|
+
Int_,
|
|
74
|
+
Int8_,
|
|
75
|
+
Int16_,
|
|
76
|
+
Int32_,
|
|
77
|
+
Int64_,
|
|
78
|
+
Pointer32_,
|
|
79
|
+
Pointer64_,
|
|
80
|
+
Bottom_,
|
|
81
|
+
Struct_,
|
|
82
|
+
Array_,
|
|
83
|
+
Float_,
|
|
84
|
+
Float32_,
|
|
85
|
+
Float64_,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
86
89
|
# lattice for 64-bit binaries
|
|
87
90
|
BASE_LATTICE_64 = networkx.DiGraph()
|
|
88
91
|
BASE_LATTICE_64.add_edge(Top_, Int_)
|
|
@@ -149,6 +152,24 @@ class SketchNode(SketchNodeBase):
|
|
|
149
152
|
def __hash__(self):
|
|
150
153
|
return hash((SketchNode, self.typevar))
|
|
151
154
|
|
|
155
|
+
@property
|
|
156
|
+
def size(self) -> int | None:
|
|
157
|
+
"""
|
|
158
|
+
Best-effort estimation of the size of the typevar (in bits). Returns None if we cannot determine.
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
if isinstance(self.typevar, DerivedTypeVariable):
|
|
162
|
+
last_label = self.typevar.labels[-1]
|
|
163
|
+
if isinstance(last_label, HasField) and last_label.bits != MAX_POINTSTO_BITS:
|
|
164
|
+
return last_label.bits
|
|
165
|
+
if isinstance(self.lower_bound, TypeConstant) and not isinstance(self.lower_bound, (TopType, BottomType)):
|
|
166
|
+
with suppress(NotImplementedError):
|
|
167
|
+
return self.lower_bound.size * 8
|
|
168
|
+
if isinstance(self.upper_bound, TypeConstant) and not isinstance(self.upper_bound, (TopType, BottomType)):
|
|
169
|
+
with suppress(NotImplementedError):
|
|
170
|
+
return self.upper_bound.size * 8
|
|
171
|
+
return None
|
|
172
|
+
|
|
152
173
|
|
|
153
174
|
class RecursiveRefNode(SketchNodeBase):
|
|
154
175
|
"""
|
|
@@ -433,9 +454,8 @@ class SimpleSolver:
|
|
|
433
454
|
if isinstance(tv, TypeVariable) and isinstance(sol, TypeConstant):
|
|
434
455
|
self.solution[tv] = sol
|
|
435
456
|
|
|
436
|
-
equ_classes, sketches, _ = self.solve()
|
|
437
457
|
self._solution_cache = {}
|
|
438
|
-
self.
|
|
458
|
+
self.solve()
|
|
439
459
|
for typevar in list(self._constraints):
|
|
440
460
|
self._convert_arrays(self._constraints[typevar])
|
|
441
461
|
|
|
@@ -448,6 +468,11 @@ class SimpleSolver:
|
|
|
448
468
|
- Build the constraint graph
|
|
449
469
|
- Collect all constraints
|
|
450
470
|
- Apply constraints to derive the lower and upper bounds
|
|
471
|
+
- Determine a solution for type variables with constraints
|
|
472
|
+
- Rewrite the constraint graph by replacing determined type variables with their solutions
|
|
473
|
+
- Solve repeatedly until all interesting type variables have solutions
|
|
474
|
+
|
|
475
|
+
By repeatedly solving until exhausting interesting type variables, we ensure the S-Trans rule is applied.
|
|
451
476
|
"""
|
|
452
477
|
|
|
453
478
|
prem_typevars = set(self._constraints) | self._typevars
|
|
@@ -476,11 +501,7 @@ class SimpleSolver:
|
|
|
476
501
|
elif isinstance(t, TypeVariable) and t in typevars:
|
|
477
502
|
constrained_typevars.add(t)
|
|
478
503
|
|
|
479
|
-
|
|
480
|
-
# TODO: Handle global variables
|
|
481
|
-
|
|
482
|
-
type_schemes = constraints
|
|
483
|
-
|
|
504
|
+
_, sketches = self.infer_shapes(typevars, constraints)
|
|
484
505
|
constraintset2tvs = defaultdict(set)
|
|
485
506
|
for idx, tv in enumerate(constrained_typevars):
|
|
486
507
|
_l.debug("Collecting constraints for type variable %r (%d/%d)", tv, idx + 1, len(constrained_typevars))
|
|
@@ -490,20 +511,43 @@ class SimpleSolver:
|
|
|
490
511
|
|
|
491
512
|
for idx, (constraint_subset, tvs) in enumerate(constraintset2tvs.items()):
|
|
492
513
|
_l.debug(
|
|
493
|
-
"Solving %d constraints for type variables %r (%d/%d)",
|
|
514
|
+
"Solving %d constraints for %d type variables %r (%d/%d)",
|
|
494
515
|
len(constraint_subset),
|
|
516
|
+
len(tvs),
|
|
495
517
|
tvs,
|
|
496
518
|
idx + 1,
|
|
497
519
|
len(constraintset2tvs),
|
|
498
520
|
)
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
primitive_constraints = self._generate_primitive_constraints(
|
|
521
|
+
|
|
522
|
+
while True:
|
|
523
|
+
base_constraint_graph = self._generate_constraint_graph(constraint_subset, tvs | PRIMITIVE_TYPES)
|
|
524
|
+
primitive_constraints = self._generate_primitive_constraints(tvs, base_constraint_graph)
|
|
525
|
+
tvs_with_primitive_constraints = set()
|
|
503
526
|
for primitive_constraint in primitive_constraints:
|
|
527
|
+
tv = self._typevar_from_primitive_constraint(primitive_constraint)
|
|
528
|
+
tvs_with_primitive_constraints.add(tv)
|
|
529
|
+
assert tv is not None, f"Cannot find type variable in primitive constraint {primitive_constraint}"
|
|
504
530
|
sketches[tv].add_constraint(primitive_constraint)
|
|
505
|
-
|
|
506
|
-
|
|
531
|
+
solutions = {}
|
|
532
|
+
self.determine(sketches, tvs_with_primitive_constraints, solutions)
|
|
533
|
+
_l.debug("Determined solutions for %d type variable(s).", len(tvs_with_primitive_constraints))
|
|
534
|
+
if not solutions:
|
|
535
|
+
break
|
|
536
|
+
|
|
537
|
+
self.solution |= solutions
|
|
538
|
+
|
|
539
|
+
tvs = {tv for tv in tvs if tv not in tvs_with_primitive_constraints}
|
|
540
|
+
if not tvs:
|
|
541
|
+
break
|
|
542
|
+
# rewrite existing constraints
|
|
543
|
+
new_constraint_subset = set()
|
|
544
|
+
for constraint in constraint_subset:
|
|
545
|
+
rewritten = self._rewrite_constraint(constraint, solutions)
|
|
546
|
+
new_constraint_subset.add(rewritten)
|
|
547
|
+
constraint_subset = new_constraint_subset
|
|
548
|
+
|
|
549
|
+
# set the solution for missing type vars to TOP
|
|
550
|
+
self.determine(sketches, set(sketches).difference(set(self.solution)), self.solution)
|
|
507
551
|
|
|
508
552
|
def infer_shapes(
|
|
509
553
|
self, typevars: set[TypeVariable], constraints: set[TypeConstraint]
|
|
@@ -593,7 +637,6 @@ class SimpleSolver:
|
|
|
593
637
|
non_primitive_endpoints: set[TypeVariable | DerivedTypeVariable],
|
|
594
638
|
constraint_graph,
|
|
595
639
|
) -> set[TypeConstraint]:
|
|
596
|
-
# FIXME: Extract interesting variables
|
|
597
640
|
constraints_0 = self._solve_constraints_between(constraint_graph, non_primitive_endpoints, PRIMITIVE_TYPES)
|
|
598
641
|
constraints_1 = self._solve_constraints_between(constraint_graph, PRIMITIVE_TYPES, non_primitive_endpoints)
|
|
599
642
|
return constraints_0 | constraints_1
|
|
@@ -612,6 +655,25 @@ class SimpleSolver:
|
|
|
612
655
|
# TODO: Other types of constraints?
|
|
613
656
|
return typevars
|
|
614
657
|
|
|
658
|
+
@staticmethod
|
|
659
|
+
def _typevar_from_primitive_constraint(constraint: TypeConstraint) -> TypeVariable | None:
|
|
660
|
+
if isinstance(constraint, Subtype):
|
|
661
|
+
if (
|
|
662
|
+
isinstance(constraint.sub_type, DerivedTypeVariable)
|
|
663
|
+
and type(constraint.sub_type.type_var) is TypeVariable
|
|
664
|
+
):
|
|
665
|
+
return constraint.sub_type.type_var
|
|
666
|
+
if type(constraint.sub_type) is TypeVariable:
|
|
667
|
+
return constraint.sub_type
|
|
668
|
+
if (
|
|
669
|
+
isinstance(constraint.super_type, DerivedTypeVariable)
|
|
670
|
+
and type(constraint.super_type.type_var) is TypeVariable
|
|
671
|
+
):
|
|
672
|
+
return constraint.super_type.type_var
|
|
673
|
+
if type(constraint.super_type) is TypeVariable:
|
|
674
|
+
return constraint.super_type
|
|
675
|
+
return None
|
|
676
|
+
|
|
615
677
|
@staticmethod
|
|
616
678
|
def _get_all_paths(
|
|
617
679
|
graph: networkx.DiGraph,
|
|
@@ -825,7 +887,6 @@ class SimpleSolver:
|
|
|
825
887
|
"""
|
|
826
888
|
|
|
827
889
|
graph = networkx.DiGraph()
|
|
828
|
-
constraints = self._get_transitive_subtype_constraints(constraints)
|
|
829
890
|
for constraint in constraints:
|
|
830
891
|
if isinstance(constraint, Subtype):
|
|
831
892
|
self._constraint_graph_add_edges(
|
|
@@ -836,33 +897,6 @@ class SimpleSolver:
|
|
|
836
897
|
self._constraint_graph_recall_forget_split(graph)
|
|
837
898
|
return graph
|
|
838
899
|
|
|
839
|
-
@staticmethod
|
|
840
|
-
def _get_transitive_subtype_constraints(constraints: set[TypeConstraint]) -> set[TypeConstraint]:
|
|
841
|
-
"""
|
|
842
|
-
Apply the S-Trans rule: a <: b, b <: c => a <: c
|
|
843
|
-
"""
|
|
844
|
-
tv2supertypes = defaultdict(set)
|
|
845
|
-
for constraint in constraints:
|
|
846
|
-
if isinstance(constraint, Subtype):
|
|
847
|
-
tv2supertypes[constraint.sub_type].add(constraint.super_type)
|
|
848
|
-
|
|
849
|
-
new_constraints = set()
|
|
850
|
-
while True:
|
|
851
|
-
changed = False
|
|
852
|
-
for subtype, supertypes in tv2supertypes.items():
|
|
853
|
-
supertypes_copy = set(supertypes)
|
|
854
|
-
for supertype in supertypes_copy:
|
|
855
|
-
if supertype in tv2supertypes:
|
|
856
|
-
for supertype_ in tv2supertypes[supertype]:
|
|
857
|
-
if supertype_ not in supertypes_copy:
|
|
858
|
-
changed = True
|
|
859
|
-
supertypes.add(supertype_)
|
|
860
|
-
new_constraints.add(Subtype(subtype, supertype_))
|
|
861
|
-
if not changed:
|
|
862
|
-
break
|
|
863
|
-
|
|
864
|
-
return constraints | new_constraints
|
|
865
|
-
|
|
866
900
|
@staticmethod
|
|
867
901
|
def _constraint_graph_add_recall_edges(graph: networkx.DiGraph, node: ConstraintGraphNode) -> None:
|
|
868
902
|
while True:
|
|
@@ -1004,12 +1038,7 @@ class SimpleSolver:
|
|
|
1004
1038
|
if typevar in typevar_set:
|
|
1005
1039
|
return True
|
|
1006
1040
|
if isinstance(typevar, Struct) and Struct_ in typevar_set:
|
|
1007
|
-
|
|
1008
|
-
return True
|
|
1009
|
-
return all(
|
|
1010
|
-
SimpleSolver._typevar_inside_set(field_typevar, typevar_set)
|
|
1011
|
-
for field_typevar in typevar.fields.values()
|
|
1012
|
-
)
|
|
1041
|
+
return True
|
|
1013
1042
|
if isinstance(typevar, Array) and Array_ in typevar_set:
|
|
1014
1043
|
return SimpleSolver._typevar_inside_set(typevar.element, typevar_set)
|
|
1015
1044
|
if isinstance(typevar, Pointer) and (Pointer32_ in typevar_set or Pointer64_ in typevar_set):
|
|
@@ -1110,31 +1139,47 @@ class SimpleSolver:
|
|
|
1110
1139
|
return Pointer64()
|
|
1111
1140
|
return t
|
|
1112
1141
|
|
|
1142
|
+
@staticmethod
|
|
1143
|
+
def _rewrite_constraint(constraint: TypeConstraint, solutions: dict) -> TypeConstraint:
|
|
1144
|
+
if isinstance(constraint, Subtype):
|
|
1145
|
+
replaced = False
|
|
1146
|
+
if isinstance(constraint.sub_type, TypeVariable) and constraint.sub_type in solutions:
|
|
1147
|
+
sub_type = solutions[constraint.sub_type]
|
|
1148
|
+
replaced = True
|
|
1149
|
+
else:
|
|
1150
|
+
sub_type = constraint.sub_type
|
|
1151
|
+
if isinstance(constraint.super_type, TypeVariable) and constraint.super_type in solutions:
|
|
1152
|
+
super_type = solutions[constraint.super_type]
|
|
1153
|
+
replaced = True
|
|
1154
|
+
else:
|
|
1155
|
+
super_type = constraint.super_type
|
|
1156
|
+
return Subtype(sub_type, super_type) if replaced else constraint
|
|
1157
|
+
return constraint
|
|
1158
|
+
|
|
1113
1159
|
def determine(
|
|
1114
1160
|
self,
|
|
1115
|
-
equivalent_classes: dict[TypeVariable, TypeVariable],
|
|
1116
1161
|
sketches,
|
|
1162
|
+
tvs,
|
|
1117
1163
|
solution: dict,
|
|
1118
1164
|
nodes: set[SketchNode] | None = None,
|
|
1119
1165
|
) -> None:
|
|
1120
1166
|
"""
|
|
1121
1167
|
Determine C-like types from sketches.
|
|
1122
1168
|
|
|
1123
|
-
:param equivalent_classes: A dictionary mapping each type variable from its representative in the equivalence
|
|
1124
|
-
class over ~.
|
|
1125
1169
|
:param sketches: A dictionary storing sketches for each type variable.
|
|
1126
1170
|
:param solution: The dictionary storing C-like types for each type variable. Output.
|
|
1127
1171
|
:param nodes: Optional. Nodes that should be considered in the sketch.
|
|
1128
1172
|
:return: None
|
|
1129
1173
|
"""
|
|
1130
|
-
for typevar, sketch in sketches.items():
|
|
1131
|
-
self._determine(equivalent_classes, typevar, sketch, solution, nodes=nodes)
|
|
1132
1174
|
|
|
1133
|
-
for
|
|
1134
|
-
|
|
1135
|
-
|
|
1175
|
+
for typevar in tvs:
|
|
1176
|
+
self._determine(typevar, sketches[typevar], solution, nodes=nodes)
|
|
1177
|
+
|
|
1178
|
+
for v, eq in self._equivalence.items():
|
|
1179
|
+
if v not in solution and eq in solution:
|
|
1180
|
+
solution[v] = solution[eq]
|
|
1136
1181
|
|
|
1137
|
-
def _determine(self,
|
|
1182
|
+
def _determine(self, the_typevar, sketch, solution: dict, nodes: set[SketchNode] | None = None):
|
|
1138
1183
|
"""
|
|
1139
1184
|
Return the solution from sketches
|
|
1140
1185
|
"""
|
|
@@ -1194,7 +1239,7 @@ class SimpleSolver:
|
|
|
1194
1239
|
for vals, out in [(func_inputs, input_args), (func_outputs, output_values)]:
|
|
1195
1240
|
for idx in range(max(vals) + 1):
|
|
1196
1241
|
if idx in vals:
|
|
1197
|
-
sol = self._determine(
|
|
1242
|
+
sol = self._determine(the_typevar, sketch, solution, nodes=vals[idx])
|
|
1198
1243
|
out.append(sol)
|
|
1199
1244
|
else:
|
|
1200
1245
|
out.append(None)
|
|
@@ -1290,7 +1335,7 @@ class SimpleSolver:
|
|
|
1290
1335
|
offset = sorted_offsets[i]
|
|
1291
1336
|
|
|
1292
1337
|
child_nodes = node_by_offset[offset]
|
|
1293
|
-
sol = self._determine(
|
|
1338
|
+
sol = self._determine(the_typevar, sketch, solution, nodes=child_nodes)
|
|
1294
1339
|
if isinstance(sol, TopType):
|
|
1295
1340
|
# make it an array if possible
|
|
1296
1341
|
elem_size = min(offset_to_sizes[offset])
|
|
@@ -1323,12 +1368,20 @@ class SimpleSolver:
|
|
|
1323
1368
|
lower_bound = Bottom_
|
|
1324
1369
|
upper_bound = Top_
|
|
1325
1370
|
|
|
1371
|
+
node_sizes = set()
|
|
1326
1372
|
for node in nodes:
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1373
|
+
node_size = node.size
|
|
1374
|
+
if node_size is not None:
|
|
1375
|
+
node_sizes.add(node_size)
|
|
1376
|
+
if len(node_sizes) > 1:
|
|
1377
|
+
# multi-sized reads - cannot converge to a reasonable type
|
|
1378
|
+
result = Bottom_
|
|
1379
|
+
else:
|
|
1380
|
+
for node in nodes:
|
|
1381
|
+
lower_bound = self.join(lower_bound, node.lower_bound)
|
|
1382
|
+
upper_bound = self.meet(upper_bound, node.upper_bound)
|
|
1383
|
+
result = lower_bound if not isinstance(lower_bound, BottomType) else upper_bound
|
|
1330
1384
|
|
|
1331
|
-
result = lower_bound if not isinstance(lower_bound, BottomType) else upper_bound
|
|
1332
1385
|
for node in nodes:
|
|
1333
1386
|
solution[node.typevar] = result
|
|
1334
1387
|
self._solution_cache[node.typevar] = result
|
|
@@ -1386,3 +1439,12 @@ class SimpleSolver:
|
|
|
1386
1439
|
if self.bits == 64:
|
|
1387
1440
|
return Pointer64
|
|
1388
1441
|
raise NotImplementedError(f"Unsupported bits {self.bits}")
|
|
1442
|
+
|
|
1443
|
+
@staticmethod
|
|
1444
|
+
def dump_constraint_graph(graph: networkx.DiGraph, filename: str) -> None:
|
|
1445
|
+
"""
|
|
1446
|
+
Dump the constraint graph to a file.
|
|
1447
|
+
"""
|
|
1448
|
+
from networkx.drawing.nx_agraph import write_dot # pylint:disable=import-outside-toplevel
|
|
1449
|
+
|
|
1450
|
+
write_dot(graph, filename)
|
|
@@ -100,7 +100,8 @@ class Typehoon(Analysis):
|
|
|
100
100
|
and not isinstance(type_.pts_to, SimTypeArray)
|
|
101
101
|
):
|
|
102
102
|
type_ = type_.pts_to
|
|
103
|
-
|
|
103
|
+
if type_ is not None:
|
|
104
|
+
type_candidates.append(type_)
|
|
104
105
|
|
|
105
106
|
# determine the best type - this logic can be made better!
|
|
106
107
|
if not type_candidates:
|
|
@@ -127,7 +127,7 @@ class Function(Serializable):
|
|
|
127
127
|
self._retout_sites: set[BlockNode] = set()
|
|
128
128
|
# block nodes (basic block nodes) at whose ends the function terminates
|
|
129
129
|
# in theory, if everything works fine, endpoints == ret_sites | jumpout_sites | callout_sites
|
|
130
|
-
self._endpoints = defaultdict(set)
|
|
130
|
+
self._endpoints: defaultdict[str, set[BlockNode]] = defaultdict(set)
|
|
131
131
|
|
|
132
132
|
self._call_sites = {}
|
|
133
133
|
self.addr = addr
|
|
@@ -1358,7 +1358,7 @@ class Function(Serializable):
|
|
|
1358
1358
|
return
|
|
1359
1359
|
|
|
1360
1360
|
graph = self.transition_graph
|
|
1361
|
-
end_addresses = defaultdict(list)
|
|
1361
|
+
end_addresses: defaultdict[int, list[BlockNode]] = defaultdict(list)
|
|
1362
1362
|
|
|
1363
1363
|
for block in self.nodes:
|
|
1364
1364
|
if isinstance(block, BlockNode):
|
|
@@ -1456,7 +1456,13 @@ class Function(Serializable):
|
|
|
1456
1456
|
)
|
|
1457
1457
|
else:
|
|
1458
1458
|
# We gotta create a new one
|
|
1459
|
-
l.error("normalize(): Please report it to Fish
|
|
1459
|
+
l.error("normalize(): Please report it to Fish.")
|
|
1460
|
+
|
|
1461
|
+
# update endpoints
|
|
1462
|
+
for sortset in self._endpoints.values():
|
|
1463
|
+
if n in sortset:
|
|
1464
|
+
sortset.remove(n)
|
|
1465
|
+
sortset.add(smallest_node)
|
|
1460
1466
|
|
|
1461
1467
|
end_addresses[end_addr] = [smallest_node]
|
|
1462
1468
|
|
|
@@ -1680,7 +1686,7 @@ class Function(Serializable):
|
|
|
1680
1686
|
n = separator
|
|
1681
1687
|
if must_disambiguate_by_addr:
|
|
1682
1688
|
n += hex(self.addr) + separator
|
|
1683
|
-
elif self.binary is not self.project.loader.main_object:
|
|
1689
|
+
elif self.binary is not self.project.loader.main_object and self.binary_name is not None:
|
|
1684
1690
|
n += self.binary_name + separator
|
|
1685
1691
|
return n + (display_name or self.name)
|
|
1686
1692
|
|
angr/lib/angr_native.dylib
CHANGED
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: angr
|
|
3
|
-
Version: 9.2.
|
|
3
|
+
Version: 9.2.153
|
|
4
4
|
Summary: A multi-architecture binary analysis toolkit, with the ability to perform dynamic symbolic execution and various static analyses on binaries
|
|
5
5
|
License: BSD-2-Clause
|
|
6
6
|
Project-URL: Homepage, https://angr.io/
|
|
@@ -17,13 +17,13 @@ Description-Content-Type: text/markdown
|
|
|
17
17
|
License-File: LICENSE
|
|
18
18
|
Requires-Dist: cxxheaderparser
|
|
19
19
|
Requires-Dist: GitPython
|
|
20
|
-
Requires-Dist: ailment==9.2.
|
|
21
|
-
Requires-Dist: archinfo==9.2.
|
|
20
|
+
Requires-Dist: ailment==9.2.153
|
|
21
|
+
Requires-Dist: archinfo==9.2.153
|
|
22
22
|
Requires-Dist: cachetools
|
|
23
23
|
Requires-Dist: capstone==5.0.3
|
|
24
24
|
Requires-Dist: cffi>=1.14.0
|
|
25
|
-
Requires-Dist: claripy==9.2.
|
|
26
|
-
Requires-Dist: cle==9.2.
|
|
25
|
+
Requires-Dist: claripy==9.2.153
|
|
26
|
+
Requires-Dist: cle==9.2.153
|
|
27
27
|
Requires-Dist: mulpyplexer
|
|
28
28
|
Requires-Dist: networkx!=2.8.1,>=2.0
|
|
29
29
|
Requires-Dist: protobuf>=5.28.2
|
|
@@ -31,7 +31,7 @@ Requires-Dist: psutil
|
|
|
31
31
|
Requires-Dist: pycparser>=2.18
|
|
32
32
|
Requires-Dist: pydemumble
|
|
33
33
|
Requires-Dist: pyformlang
|
|
34
|
-
Requires-Dist: pyvex==9.2.
|
|
34
|
+
Requires-Dist: pyvex==9.2.153
|
|
35
35
|
Requires-Dist: rich>=13.1.0
|
|
36
36
|
Requires-Dist: sortedcontainers
|
|
37
37
|
Requires-Dist: sympy
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
angr/__init__.py,sha256=
|
|
1
|
+
angr/__init__.py,sha256=ApROccv7-zzv89AOX-4Ox3WeQbu3W39xfautbq4aWfk,9153
|
|
2
2
|
angr/__main__.py,sha256=AK9V6uPZ58UuTKmmiH_Kgn5pG9AvjnmJCPOku69A-WU,4993
|
|
3
3
|
angr/annocfg.py,sha256=0NIvcuCskwz45hbBzigUTAuCrYutjDMwEXtMJf0y0S0,10742
|
|
4
4
|
angr/blade.py,sha256=NhesOPloKJC1DQJRv_HBT18X7oNxK16JwAfNz2Lc1o0,15384
|
|
@@ -54,7 +54,7 @@ angr/analyses/proximity_graph.py,sha256=-g7pNpbP2HQhKW3w1Eff23K8vAsgWWYoe3wVxRh3
|
|
|
54
54
|
angr/analyses/reassembler.py,sha256=UXrDQNJtn4RUurpbIyMVpQ3AZ0VGVQZatoGHziEHvU0,98357
|
|
55
55
|
angr/analyses/s_liveness.py,sha256=K4soSrcQE9pIn7Yf2Lb3LZEu1ymuQVpWzOqLKunFDGQ,7974
|
|
56
56
|
angr/analyses/s_propagator.py,sha256=4MUmjo1aozCT-UeN9IMYlxtMjCoTM6hWwYaYTTjwvCQ,24904
|
|
57
|
-
angr/analyses/smc.py,sha256=
|
|
57
|
+
angr/analyses/smc.py,sha256=UyVaTBms0KI9jRUBhbnz1s6ez_K_oRy4qoPsvxwnoQY,5177
|
|
58
58
|
angr/analyses/soot_class_hierarchy.py,sha256=R4xeacn-a_Q7PxSyj_stu5mnglZkPB5US5srKChX3mk,8740
|
|
59
59
|
angr/analyses/stack_pointer_tracker.py,sha256=XcqCwqurI8x-N4mU_yfQWwIQNkj3fTtXYkUvw2PFIzw,37821
|
|
60
60
|
angr/analyses/static_hooker.py,sha256=AYJXoHtdq2m-MgpJbx4eur7wy7llrKXvsVM5NdPcKHU,1852
|
|
@@ -71,9 +71,9 @@ angr/analyses/cfg/__init__.py,sha256=-w8Vd6FD6rtjlQaQ7MxwmliFgS2zt-kZepAY4gHas04
|
|
|
71
71
|
angr/analyses/cfg/cfb.py,sha256=scykl1FJvqcTe2x69zreWi0PG_zYMbka3k6tlRwaD_g,15367
|
|
72
72
|
angr/analyses/cfg/cfg.py,sha256=dc9M91CaLeEKduYfMwpsT_01x6XyYuoNvgvcDKtbN-I,3177
|
|
73
73
|
angr/analyses/cfg/cfg_arch_options.py,sha256=_XRewFZ51SeNaxChadb6_ER7-8LW8KXeTIpoP8_iRj0,3506
|
|
74
|
-
angr/analyses/cfg/cfg_base.py,sha256=
|
|
74
|
+
angr/analyses/cfg/cfg_base.py,sha256=VEsUvo4ySnvMvrphcJjAhCHfh7BX9jmY7KrHc2U_Hgc,123441
|
|
75
75
|
angr/analyses/cfg/cfg_emulated.py,sha256=wL0ABJMZ8EwKbNjrpE_eqCkZpHDt4y6lmoQOmAIcJMQ,148235
|
|
76
|
-
angr/analyses/cfg/cfg_fast.py,sha256=
|
|
76
|
+
angr/analyses/cfg/cfg_fast.py,sha256=nZVk_Wm1ylS3acBYKN_TDD-8sKg67Gg7mhOI54TYfrA,230949
|
|
77
77
|
angr/analyses/cfg/cfg_fast_soot.py,sha256=8YgMtY_8w4nAMcHR6n-q_eFvKwsvNz0anUH7EzIL1B4,25924
|
|
78
78
|
angr/analyses/cfg/cfg_job_base.py,sha256=Zshze972MakTsd-licQz77lac17igQaaTsAteHeHhYQ,5974
|
|
79
79
|
angr/analyses/cfg/indirect_jump_resolvers/__init__.py,sha256=qWiTSIAQgXWmaYa9YYaiKsSTwUVClymaXv9sCX-bY-k,835
|
|
@@ -101,13 +101,13 @@ angr/analyses/data_dep/data_dependency_analysis.py,sha256=_vQPkw1NMrzD7kAFeotOaa
|
|
|
101
101
|
angr/analyses/data_dep/dep_nodes.py,sha256=LcNcxeuKXMMc0GkmvKqqFwNlAk3GhzBR8ixM4CD305k,4640
|
|
102
102
|
angr/analyses/data_dep/sim_act_location.py,sha256=EXmfFF3lV9XogcB2gFRMUoJCbjpDYiSKNyfafkBfiY8,1564
|
|
103
103
|
angr/analyses/decompiler/__init__.py,sha256=eyxt2UKvPkbuS_l_1GPb0CJ6hrj2wTavh-mVf23wwiQ,1162
|
|
104
|
-
angr/analyses/decompiler/ail_simplifier.py,sha256=
|
|
104
|
+
angr/analyses/decompiler/ail_simplifier.py,sha256=x6B5ex0eoZgH80yLmMZbXViZKYZI1NU77cibN30qpfs,79886
|
|
105
105
|
angr/analyses/decompiler/ailgraph_walker.py,sha256=m71HCthOr9J8PZoMxJzCPskay8yfCZ2j8esWT4Ka3KI,1630
|
|
106
106
|
angr/analyses/decompiler/block_io_finder.py,sha256=xMwG8Bi69OGNYVs0U0F4yxM8kEsnyrsMrf0gEr8dOEw,10923
|
|
107
107
|
angr/analyses/decompiler/block_similarity.py,sha256=SseCdWgh-kS9q_C_BRxlQ4OwCRQfg-9IyncxKXm_OG8,6849
|
|
108
108
|
angr/analyses/decompiler/block_simplifier.py,sha256=Di5UXgBIXp0pa3_ubHY4k9vj927xAFR3oCUZ16Q3WvE,14229
|
|
109
109
|
angr/analyses/decompiler/callsite_maker.py,sha256=ZjtLdxDCLS0WPqOik9bCek2LyuAtQNYA4V-yqGLeENo,23032
|
|
110
|
-
angr/analyses/decompiler/clinic.py,sha256=
|
|
110
|
+
angr/analyses/decompiler/clinic.py,sha256=5gs11WIfT7HAFKvVGdPjQHgrMRO8SXHw2zra1r9j63A,146384
|
|
111
111
|
angr/analyses/decompiler/condition_processor.py,sha256=61VDwVA1e-oKsv0N8kvh3c5QOdQixrkBZcm3RLuw7KU,52679
|
|
112
112
|
angr/analyses/decompiler/decompilation_cache.py,sha256=oNkeyrEXhyinrN7-fKeDEuGP6I_oAclGjRS4Aa36FoE,1488
|
|
113
113
|
angr/analyses/decompiler/decompilation_options.py,sha256=NDB67DI1L-stvJ4b1eQkfV26HgDJ_rG9-6PEv08G9-8,8195
|
|
@@ -120,7 +120,7 @@ angr/analyses/decompiler/jump_target_collector.py,sha256=qR11VsIp6H1N-19xCdXMRs1
|
|
|
120
120
|
angr/analyses/decompiler/jumptable_entry_condition_rewriter.py,sha256=f_JyNiSZfoudElfl2kIzONoYCiosR4xYFOe8Q5SkvLg,2176
|
|
121
121
|
angr/analyses/decompiler/label_collector.py,sha256=JLaGuSZu-DdJMBTYOPt4QpWJ6UigOpsC5bgNANrSao4,798
|
|
122
122
|
angr/analyses/decompiler/redundant_label_remover.py,sha256=J9hpP3C_P08v84FjVU0q5Rmj5M1N9q3HKWSWsA2u7Yg,5879
|
|
123
|
-
angr/analyses/decompiler/region_identifier.py,sha256=
|
|
123
|
+
angr/analyses/decompiler/region_identifier.py,sha256=YsJp16bHNOEvhHYu0Dw1tAorm2eM84DsxF4Ilwh5htw,51184
|
|
124
124
|
angr/analyses/decompiler/region_walker.py,sha256=u0hR0bEX1hSwkv-vejIM1gS-hcX2F2DLsDqpKhQ5_pQ,752
|
|
125
125
|
angr/analyses/decompiler/return_maker.py,sha256=pKn9_y5VXqTeJnD5uzLLd9sH_Dp_9wkPcWPiJPTV-7A,2550
|
|
126
126
|
angr/analyses/decompiler/seq_to_blocks.py,sha256=bB-1m8oBO59AlAp6izAROks3BBxFW8zigLlrIMt6Yfs,564
|
|
@@ -363,10 +363,10 @@ angr/analyses/s_reaching_definitions/s_reaching_definitions.py,sha256=_SooCn9qpw
|
|
|
363
363
|
angr/analyses/typehoon/__init__.py,sha256=KjKBUZadAd3grXUy48_qO0L4Me-riSqPGteVDcTL59M,92
|
|
364
364
|
angr/analyses/typehoon/dfa.py,sha256=41lzhE-QmkC342SjfaaPI41lr4Au5XROTu_7oenvg7g,3823
|
|
365
365
|
angr/analyses/typehoon/lifter.py,sha256=hxYJmM_A0Kl6YgY7NyWBtA3ieaY49Ey3ESCHC61lMys,4000
|
|
366
|
-
angr/analyses/typehoon/simple_solver.py,sha256=
|
|
366
|
+
angr/analyses/typehoon/simple_solver.py,sha256=QMHPHz6veiu6xp9BeeTTumi5ispgjCnNo_IP8ESiFE0,57495
|
|
367
367
|
angr/analyses/typehoon/translator.py,sha256=_UE1JC4KNDXXl4plula9OApK1ee07z9BFdX9HKa5uqw,10568
|
|
368
368
|
angr/analyses/typehoon/typeconsts.py,sha256=jQEVziyt3LnctrSrCtbUSPi-0tjl8DKoLMFfaOEG3lI,7939
|
|
369
|
-
angr/analyses/typehoon/typehoon.py,sha256=
|
|
369
|
+
angr/analyses/typehoon/typehoon.py,sha256=IXC_a2N7hsq8wwUrx_UITzmjTApMZWVGYxYBtS3PBL8,12152
|
|
370
370
|
angr/analyses/typehoon/typevars.py,sha256=cvbeeEDapb0LgGgtgUVpbhAcfuaylk7vEiwCqPxvtQo,16332
|
|
371
371
|
angr/analyses/typehoon/variance.py,sha256=3wYw3of8uoar-MQ7gD6arALiwlJRW990t0BUqMarXIY,193
|
|
372
372
|
angr/analyses/unpacker/__init__.py,sha256=tBXwDMFKN0Hp8YP0DK-c6deo0Muc_LNopvoKKbzp3Tc,190
|
|
@@ -542,7 +542,7 @@ angr/knowledge_plugins/cfg/cfg_node.py,sha256=mAvQ8XAEURM7y0suc_S9lfxCmfXSTJHmWB
|
|
|
542
542
|
angr/knowledge_plugins/cfg/indirect_jump.py,sha256=W3KWpH7Sx-6Z7h_BwQjCK_XfP3ce_MaeAu_Aaq3D3qg,2072
|
|
543
543
|
angr/knowledge_plugins/cfg/memory_data.py,sha256=QLxFZfrtwz8u6UJn1L-Sxa-C8S0Gy9IOlfNfHCLPIow,5056
|
|
544
544
|
angr/knowledge_plugins/functions/__init__.py,sha256=asiLNiT6sHbjP6eU-kDpawIoVxv4J35cwz5yQHtQ2E0,167
|
|
545
|
-
angr/knowledge_plugins/functions/function.py,sha256=
|
|
545
|
+
angr/knowledge_plugins/functions/function.py,sha256=vzpTLise4KKkLkQwq9LRYZ4NUkioh-zZphwBIG74euY,70770
|
|
546
546
|
angr/knowledge_plugins/functions/function_manager.py,sha256=YWp9Hc-Rx9iYChJ3hFv9Tjat-6ZUidv1xsSZLQ2tL9Q,20469
|
|
547
547
|
angr/knowledge_plugins/functions/function_parser.py,sha256=DTdVwYt6nXLMc0EOh-V_GhvZYQ947UNBaA77qn7Y6Vo,12379
|
|
548
548
|
angr/knowledge_plugins/functions/soot_function.py,sha256=OzCvQPWxnjbwPWTW0JXrQey4zyaayHD_v6ZA7nJ4YJw,4850
|
|
@@ -572,7 +572,7 @@ angr/knowledge_plugins/xrefs/__init__.py,sha256=5PhqVOtTZ27lCjJ9wp7akUeJydqILbyC
|
|
|
572
572
|
angr/knowledge_plugins/xrefs/xref.py,sha256=U2H1rfffp5EXoh0awlGxMBxA4K5MIwl3CXjV3Uih3tA,4856
|
|
573
573
|
angr/knowledge_plugins/xrefs/xref_manager.py,sha256=1n373rtV91xicAfSUresRigsZ6qCBhPOaJKrN_SW3QY,4157
|
|
574
574
|
angr/knowledge_plugins/xrefs/xref_types.py,sha256=LcQ9pD4E4XlC51Us49xiqAoGAFGpnCrpYO4mOzILiKI,308
|
|
575
|
-
angr/lib/angr_native.dylib,sha256=
|
|
575
|
+
angr/lib/angr_native.dylib,sha256=cs8PMMcioRlRAwJSNsOaMGCN9bPxiBssvnyxhQoKdFc,234064
|
|
576
576
|
angr/misc/__init__.py,sha256=FoUwjk1DhqlIsr2sBN0MlR8MnSOGQv9QJhxmq32RYuA,355
|
|
577
577
|
angr/misc/ansi.py,sha256=nPJHC0SKfqasMQZ0LxdmmIYojjmk4nr5jI6FrzoTwS0,811
|
|
578
578
|
angr/misc/autoimport.py,sha256=iZagpuPwZWczUTYIqs-JkDMQjftMqc_cchcm7OBFiEg,3450
|
|
@@ -1384,9 +1384,9 @@ angr/utils/types.py,sha256=5EDtrusFLf1fIcMz8fgJiPPsUhpEm0bf_oqZ_PSRje0,1836
|
|
|
1384
1384
|
angr/utils/ssa/__init__.py,sha256=ZUPoK7Y1k-7vQkvoYUYPMdjfGh4oC6W3VbWzV_udZHg,14020
|
|
1385
1385
|
angr/utils/ssa/tmp_uses_collector.py,sha256=rSpvMxBHzg-tmvhsfjn3iLyPEKzaZN-xpQrdslMq3J4,793
|
|
1386
1386
|
angr/utils/ssa/vvar_uses_collector.py,sha256=O2aNZeM5DL8qatyhYuMhgbYGFp6Onm2yr9pKq1wRjA0,1347
|
|
1387
|
-
angr-9.2.
|
|
1388
|
-
angr-9.2.
|
|
1389
|
-
angr-9.2.
|
|
1390
|
-
angr-9.2.
|
|
1391
|
-
angr-9.2.
|
|
1392
|
-
angr-9.2.
|
|
1387
|
+
angr-9.2.153.dist-info/licenses/LICENSE,sha256=PmWf0IlSz6Jjp9n7nyyBQA79Q5C2ma68LRykY1V3GF0,1456
|
|
1388
|
+
angr-9.2.153.dist-info/METADATA,sha256=EiC80ame406IE0Q0DeYLVD3JFIgtsPhFSjq7A5yiI1g,4910
|
|
1389
|
+
angr-9.2.153.dist-info/WHEEL,sha256=phXSQwFx8UMSLA_kjHKU7vA4cZV1oy_BrKf8FXPlNwA,105
|
|
1390
|
+
angr-9.2.153.dist-info/entry_points.txt,sha256=Vjh1C8PMyr5dZFMnik5WkEP01Uwr2T73I3a6N32sgQU,44
|
|
1391
|
+
angr-9.2.153.dist-info/top_level.txt,sha256=dKw0KWTbwLXytFvv15oAAG4sUs3ey47tt6DorJG9-hw,5
|
|
1392
|
+
angr-9.2.153.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|