angr 9.2.147__py3-none-manylinux2014_aarch64.whl → 9.2.148__py3-none-manylinux2014_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/analysis.py +3 -11
- angr/analyses/calling_convention/fact_collector.py +5 -4
- angr/analyses/calling_convention/utils.py +1 -0
- angr/analyses/cfg/cfg_base.py +3 -59
- angr/analyses/cfg/cfg_emulated.py +12 -12
- angr/analyses/cfg/cfg_fast.py +20 -17
- angr/analyses/cfg/cfg_fast_soot.py +3 -3
- angr/analyses/decompiler/callsite_maker.py +28 -18
- angr/analyses/decompiler/clinic.py +4 -4
- angr/analyses/decompiler/condition_processor.py +0 -21
- angr/analyses/decompiler/counters/call_counter.py +3 -0
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +14 -0
- angr/analyses/decompiler/structured_codegen/c.py +5 -5
- angr/analyses/decompiler/structuring/phoenix.py +11 -3
- angr/analyses/deobfuscator/api_obf_finder.py +5 -1
- angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
- angr/analyses/forward_analysis/visitors/graph.py +0 -8
- angr/analyses/identifier/runner.py +1 -1
- angr/analyses/reaching_definitions/function_handler.py +4 -4
- angr/analyses/reassembler.py +1 -1
- angr/analyses/stack_pointer_tracker.py +1 -1
- angr/analyses/static_hooker.py +11 -9
- angr/analyses/variable_recovery/engine_ail.py +8 -8
- angr/analyses/variable_recovery/engine_base.py +2 -0
- angr/calling_conventions.py +74 -23
- angr/exploration_techniques/director.py +1 -1
- angr/knowledge_plugins/functions/function.py +41 -38
- angr/knowledge_plugins/functions/function_manager.py +9 -0
- angr/knowledge_plugins/functions/function_parser.py +9 -1
- angr/knowledge_plugins/functions/soot_function.py +1 -1
- angr/knowledge_plugins/key_definitions/key_definition_manager.py +1 -1
- angr/procedures/definitions/__init__.py +14 -11
- angr/procedures/stubs/format_parser.py +1 -1
- angr/project.py +23 -29
- angr/protos/cfg_pb2.py +14 -25
- angr/protos/function_pb2.py +11 -22
- angr/protos/primitives_pb2.py +36 -47
- angr/protos/variables_pb2.py +28 -39
- angr/protos/xrefs_pb2.py +8 -19
- angr/sim_type.py +0 -16
- angr/simos/cgc.py +1 -1
- angr/simos/linux.py +5 -5
- angr/simos/windows.py +5 -5
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -1
- {angr-9.2.147.dist-info → angr-9.2.148.dist-info}/METADATA +8 -7
- {angr-9.2.147.dist-info → angr-9.2.148.dist-info}/RECORD +52 -52
- {angr-9.2.147.dist-info → angr-9.2.148.dist-info}/WHEEL +1 -1
- {angr-9.2.147.dist-info → angr-9.2.148.dist-info}/entry_points.txt +0 -0
- {angr-9.2.147.dist-info → angr-9.2.148.dist-info/licenses}/LICENSE +0 -0
- {angr-9.2.147.dist-info → angr-9.2.148.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
angr/analyses/analysis.py
CHANGED
|
@@ -18,7 +18,6 @@ import typing
|
|
|
18
18
|
from rich import progress
|
|
19
19
|
|
|
20
20
|
from angr.misc.plugins import PluginVendor, VendorPreset
|
|
21
|
-
from angr.misc.ux import deprecated
|
|
22
21
|
from angr.misc import telemetry
|
|
23
22
|
from angr.misc.testing import is_testing
|
|
24
23
|
|
|
@@ -121,10 +120,6 @@ class AnalysesHub(PluginVendor[A]):
|
|
|
121
120
|
super().__init__()
|
|
122
121
|
self.project = project
|
|
123
122
|
|
|
124
|
-
@deprecated()
|
|
125
|
-
def reload_analyses(self): # pylint: disable=no-self-use
|
|
126
|
-
return
|
|
127
|
-
|
|
128
123
|
def _init_plugin(self, plugin_cls: type[A]) -> AnalysisFactory[A]:
|
|
129
124
|
return AnalysisFactory(self.project, plugin_cls)
|
|
130
125
|
|
|
@@ -392,12 +387,9 @@ class Analysis:
|
|
|
392
387
|
|
|
393
388
|
def __getstate__(self):
|
|
394
389
|
d = dict(self.__dict__)
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
del d["_progress_callback"]
|
|
399
|
-
if "_statusbar" in d:
|
|
400
|
-
del d["_statusbar"]
|
|
390
|
+
d.pop("_progressbar", None)
|
|
391
|
+
d.pop("_progress_callback", None)
|
|
392
|
+
d.pop("_statusbar", None)
|
|
401
393
|
return d
|
|
402
394
|
|
|
403
395
|
def __setstate__(self, state):
|
|
@@ -445,10 +445,11 @@ class FactCollector(Analysis):
|
|
|
445
445
|
if func_succ.prototype_libname is not None:
|
|
446
446
|
# we need to deref the prototype in case it uses SimTypeRef internally
|
|
447
447
|
type_collections = []
|
|
448
|
-
prototype_lib
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
448
|
+
for prototype_lib in SIM_LIBRARIES[func_succ.prototype_libname]:
|
|
449
|
+
if prototype_lib.type_collection_names:
|
|
450
|
+
for typelib_name in prototype_lib.type_collection_names:
|
|
451
|
+
type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
|
|
452
|
+
if type_collections:
|
|
452
453
|
proto = dereference_simtype(proto, type_collections)
|
|
453
454
|
|
|
454
455
|
assert isinstance(proto, SimTypeFunction) and proto.returnty is not None
|
|
@@ -35,6 +35,7 @@ def is_sane_register_variable(
|
|
|
35
35
|
return 16 <= reg_offset < 80 # x0-x7
|
|
36
36
|
|
|
37
37
|
if arch_name == "AMD64":
|
|
38
|
+
# TODO is rbx ever a register?
|
|
38
39
|
return 24 <= reg_offset < 40 or 64 <= reg_offset < 104 # rcx, rdx # rsi, rdi, r8, r9, r10
|
|
39
40
|
# 224 <= reg_offset < 480) # xmm0-xmm7
|
|
40
41
|
|
angr/analyses/cfg/cfg_base.py
CHANGED
|
@@ -17,7 +17,6 @@ from archinfo.arch_arm import is_arm_arch, get_real_address_if_arm
|
|
|
17
17
|
from angr.knowledge_plugins.functions.function_manager import FunctionManager
|
|
18
18
|
from angr.knowledge_plugins.functions.function import Function
|
|
19
19
|
from angr.knowledge_plugins.cfg import IndirectJump, CFGNode, CFGENode, CFGModel # pylint:disable=unused-import
|
|
20
|
-
from angr.misc.ux import deprecated
|
|
21
20
|
from angr.procedures.stubs.UnresolvableJumpTarget import UnresolvableJumpTarget
|
|
22
21
|
from angr.utils.constants import DEFAULT_STATEMENT
|
|
23
22
|
from angr.procedures.procedure_dict import SIM_PROCEDURES
|
|
@@ -354,64 +353,9 @@ class CFGBase(Analysis):
|
|
|
354
353
|
|
|
355
354
|
raise NotImplementedError("I'm too lazy to implement it right now")
|
|
356
355
|
|
|
357
|
-
@deprecated(replacement="self.model.get_predecessors()")
|
|
358
|
-
def get_predecessors(self, cfgnode, excluding_fakeret=True, jumpkind=None):
|
|
359
|
-
return self._model.get_predecessors(cfgnode, excluding_fakeret=excluding_fakeret, jumpkind=jumpkind)
|
|
360
|
-
|
|
361
|
-
@deprecated(replacement="self.model.get_successors()")
|
|
362
|
-
def get_successors(self, node, excluding_fakeret=True, jumpkind=None):
|
|
363
|
-
return self._model.get_successors(node, excluding_fakeret=excluding_fakeret, jumpkind=jumpkind)
|
|
364
|
-
|
|
365
|
-
@deprecated(replacement="self.model.get_successors_and_jumpkind")
|
|
366
|
-
def get_successors_and_jumpkind(self, node, excluding_fakeret=True):
|
|
367
|
-
return self._model.get_successors_and_jumpkind(node, excluding_fakeret=excluding_fakeret)
|
|
368
|
-
|
|
369
|
-
@deprecated(replacement="self.model.get_all_predecessors()")
|
|
370
|
-
def get_all_predecessors(self, cfgnode, depth_limit=None):
|
|
371
|
-
return self._model.get_all_predecessors(cfgnode, depth_limit)
|
|
372
|
-
|
|
373
|
-
@deprecated(replacement="self.model.get_all_successors()")
|
|
374
|
-
def get_all_successors(self, cfgnode, depth_limit=None):
|
|
375
|
-
return self._model.get_all_successors(cfgnode, depth_limit)
|
|
376
|
-
|
|
377
|
-
@deprecated(replacement="self.model.get_node()")
|
|
378
|
-
def get_node(self, block_id):
|
|
379
|
-
return self._model.get_node(block_id)
|
|
380
|
-
|
|
381
|
-
@deprecated(replacement="self.model.get_any_node()")
|
|
382
|
-
def get_any_node(self, addr, is_syscall=None, anyaddr=False, force_fastpath=False):
|
|
383
|
-
return self._model.get_any_node(addr, is_syscall=is_syscall, anyaddr=anyaddr, force_fastpath=force_fastpath)
|
|
384
|
-
|
|
385
|
-
@deprecated(replacement="self.model.get_all_nodes()")
|
|
386
|
-
def get_all_nodes(self, addr, is_syscall=None, anyaddr=False):
|
|
387
|
-
return self._model.get_all_nodes(addr, is_syscall=is_syscall, anyaddr=anyaddr)
|
|
388
|
-
|
|
389
|
-
@deprecated(replacement="self.model.nodes()")
|
|
390
|
-
def nodes(self):
|
|
391
|
-
return self._model.nodes()
|
|
392
|
-
|
|
393
|
-
@deprecated(replacement="nodes")
|
|
394
|
-
def nodes_iter(self):
|
|
395
|
-
"""
|
|
396
|
-
(Decrepated) An iterator of all nodes in the graph. Will be removed in the future.
|
|
397
|
-
|
|
398
|
-
:return: The iterator.
|
|
399
|
-
:rtype: iterator
|
|
400
|
-
"""
|
|
401
|
-
|
|
402
|
-
return self.nodes()
|
|
403
|
-
|
|
404
356
|
def get_loop_back_edges(self):
|
|
405
357
|
return self._loop_back_edges
|
|
406
358
|
|
|
407
|
-
@deprecated(replacement="self.model.get_branching_nodes()")
|
|
408
|
-
def get_branching_nodes(self):
|
|
409
|
-
return self._model.get_branching_nodes()
|
|
410
|
-
|
|
411
|
-
@deprecated(replacement="self.model.get_exit_stmt_idx")
|
|
412
|
-
def get_exit_stmt_idx(self, src_block, dst_block):
|
|
413
|
-
return self._model.get_exit_stmt_idx(src_block, dst_block)
|
|
414
|
-
|
|
415
359
|
@property
|
|
416
360
|
def graph(self) -> networkx.DiGraph[CFGNode]:
|
|
417
361
|
raise NotImplementedError
|
|
@@ -1555,7 +1499,7 @@ class CFGBase(Analysis):
|
|
|
1555
1499
|
):
|
|
1556
1500
|
# all nops. mark this function as a function alignment
|
|
1557
1501
|
l.debug("Function chunk %#x is probably used as a function alignment (all nops).", func_addr)
|
|
1558
|
-
self.kb.functions[func_addr].
|
|
1502
|
+
self.kb.functions[func_addr].is_alignment = True
|
|
1559
1503
|
continue
|
|
1560
1504
|
node = function.get_node(block.addr)
|
|
1561
1505
|
assert node is not None
|
|
@@ -1563,7 +1507,7 @@ class CFGBase(Analysis):
|
|
|
1563
1507
|
if len(successors) == 1 and successors[0].addr == node.addr:
|
|
1564
1508
|
# self loop. mark this function as a function alignment
|
|
1565
1509
|
l.debug("Function chunk %#x is probably used as a function alignment (self-loop).", func_addr)
|
|
1566
|
-
self.kb.functions[func_addr].
|
|
1510
|
+
self.kb.functions[func_addr].is_alignment = True
|
|
1567
1511
|
continue
|
|
1568
1512
|
|
|
1569
1513
|
def make_functions(self):
|
|
@@ -2110,7 +2054,7 @@ class CFGBase(Analysis):
|
|
|
2110
2054
|
continue
|
|
2111
2055
|
if func_addr in jumptable_entries:
|
|
2112
2056
|
# is there any call edge pointing to it?
|
|
2113
|
-
func_node = self.get_any_node(func_addr, force_fastpath=True)
|
|
2057
|
+
func_node = self.model.get_any_node(func_addr, force_fastpath=True)
|
|
2114
2058
|
if func_node is not None:
|
|
2115
2059
|
in_edges = self.graph.in_edges(func_node, data=True)
|
|
2116
2060
|
has_transition_pred = None
|
|
@@ -472,7 +472,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
472
472
|
src_blocknode: BlockNode = back_edge[0]
|
|
473
473
|
dst_blocknode: BlockNode = back_edge[1]
|
|
474
474
|
|
|
475
|
-
for src in self.get_all_nodes(src_blocknode.addr):
|
|
475
|
+
for src in self.model.get_all_nodes(src_blocknode.addr):
|
|
476
476
|
for dst in graph.successors(src):
|
|
477
477
|
if dst.addr != dst_blocknode.addr:
|
|
478
478
|
continue
|
|
@@ -524,7 +524,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
524
524
|
start = self._starts[0]
|
|
525
525
|
if isinstance(start, tuple):
|
|
526
526
|
start, _ = start # pylint: disable=unpacking-non-sequence
|
|
527
|
-
start_node = self.get_any_node(start)
|
|
527
|
+
start_node = self.model.get_any_node(start)
|
|
528
528
|
if start_node is None:
|
|
529
529
|
raise AngrCFGError("Cannot find start node when trying to unroll loops. The CFG might be empty.")
|
|
530
530
|
|
|
@@ -720,7 +720,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
720
720
|
# FIXME: syscalls are not supported
|
|
721
721
|
# FIXME: start should also take a CFGNode instance
|
|
722
722
|
|
|
723
|
-
start_node = self.get_any_node(start)
|
|
723
|
+
start_node = self.model.get_any_node(start)
|
|
724
724
|
assert start_node is not None
|
|
725
725
|
|
|
726
726
|
node_wrapper = (start_node, 0)
|
|
@@ -2286,9 +2286,9 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
2286
2286
|
# Remove that edge!
|
|
2287
2287
|
graph.remove_edge(call_func_addr, return_to_addr)
|
|
2288
2288
|
# Remove the edge in CFG
|
|
2289
|
-
nodes = self.get_all_nodes(callsite_block_addr)
|
|
2289
|
+
nodes = self.model.get_all_nodes(callsite_block_addr)
|
|
2290
2290
|
for n in nodes:
|
|
2291
|
-
successors = self.get_successors_and_jumpkind(n, excluding_fakeret=False)
|
|
2291
|
+
successors = self.model.get_successors_and_jumpkind(n, excluding_fakeret=False)
|
|
2292
2292
|
for successor, jumpkind in successors:
|
|
2293
2293
|
if jumpkind == "Ijk_FakeRet" and successor.addr == return_to_addr:
|
|
2294
2294
|
self.remove_edge(n, successor)
|
|
@@ -2548,7 +2548,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
2548
2548
|
for start in starts:
|
|
2549
2549
|
l.debug("Start symbolic execution at 0x%x on program slice.", start)
|
|
2550
2550
|
# Get the state from our CFG
|
|
2551
|
-
node = self.get_any_node(start)
|
|
2551
|
+
node = self.model.get_any_node(start)
|
|
2552
2552
|
if node is None:
|
|
2553
2553
|
# Well, we have to live with an empty state
|
|
2554
2554
|
base_state = self.project.factory.blank_state(addr=start)
|
|
@@ -2561,7 +2561,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
2561
2561
|
initial_nodes = [n for n in bc.taint_graph.nodes() if bc.taint_graph.in_degree(n) == 0]
|
|
2562
2562
|
for cl in initial_nodes:
|
|
2563
2563
|
# Iterate in all actions of this node, and pick corresponding actions
|
|
2564
|
-
cfg_nodes = self.get_all_nodes(cl.block_addr)
|
|
2564
|
+
cfg_nodes = self.model.get_all_nodes(cl.block_addr)
|
|
2565
2565
|
for n in cfg_nodes:
|
|
2566
2566
|
if not n.final_states:
|
|
2567
2567
|
continue
|
|
@@ -3376,9 +3376,9 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
3376
3376
|
|
|
3377
3377
|
all_predecessors = []
|
|
3378
3378
|
|
|
3379
|
-
nodes = self.get_all_nodes(function_address)
|
|
3379
|
+
nodes = self.model.get_all_nodes(function_address)
|
|
3380
3380
|
for n in nodes:
|
|
3381
|
-
predecessors = list(self.get_predecessors(n))
|
|
3381
|
+
predecessors = list(self.model.get_predecessors(n))
|
|
3382
3382
|
all_predecessors.extend(predecessors)
|
|
3383
3383
|
|
|
3384
3384
|
return all_predecessors
|
|
@@ -3391,8 +3391,8 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
3391
3391
|
Return: a list of lists of nodes representing paths.
|
|
3392
3392
|
"""
|
|
3393
3393
|
if isinstance(begin, int) and isinstance(end, int):
|
|
3394
|
-
n_begin = self.get_any_node(begin)
|
|
3395
|
-
n_end = self.get_any_node(end)
|
|
3394
|
+
n_begin = self.model.get_any_node(begin)
|
|
3395
|
+
n_end = self.model.get_any_node(end)
|
|
3396
3396
|
|
|
3397
3397
|
elif isinstance(begin, CFGENode) and isinstance(end, CFGENode):
|
|
3398
3398
|
n_begin = begin
|
|
@@ -3417,7 +3417,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
3417
3417
|
|
|
3418
3418
|
for ep in self._entry_points:
|
|
3419
3419
|
# FIXME: This is not always correct. We'd better store CFGNodes in self._entry_points
|
|
3420
|
-
ep_node = self.get_any_node(ep)
|
|
3420
|
+
ep_node = self.model.get_any_node(ep)
|
|
3421
3421
|
|
|
3422
3422
|
if not ep_node:
|
|
3423
3423
|
continue
|
angr/analyses/cfg/cfg_fast.py
CHANGED
|
@@ -22,10 +22,10 @@ from archinfo.arch_soot import SootAddressDescriptor
|
|
|
22
22
|
from archinfo.arch_arm import is_arm_arch, get_real_address_if_arm
|
|
23
23
|
|
|
24
24
|
from angr.analyses import AnalysesHub
|
|
25
|
+
from angr.misc.ux import once
|
|
25
26
|
from angr.knowledge_plugins.cfg import CFGNode, MemoryDataSort, MemoryData, IndirectJump, IndirectJumpType
|
|
26
27
|
from angr.knowledge_plugins.xrefs import XRef, XRefType
|
|
27
28
|
from angr.knowledge_plugins.functions import Function
|
|
28
|
-
from angr.misc.ux import deprecated
|
|
29
29
|
from angr.codenode import HookNode
|
|
30
30
|
from angr import sim_options as o
|
|
31
31
|
from angr.errors import (
|
|
@@ -589,10 +589,10 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
589
589
|
regions=None,
|
|
590
590
|
pickle_intermediate_results=False,
|
|
591
591
|
symbols=True,
|
|
592
|
-
function_prologues=
|
|
592
|
+
function_prologues: bool | None = None,
|
|
593
593
|
resolve_indirect_jumps=True,
|
|
594
594
|
force_segment=False,
|
|
595
|
-
force_smart_scan=
|
|
595
|
+
force_smart_scan: bool | None = None,
|
|
596
596
|
force_complete_scan=False,
|
|
597
597
|
indirect_jump_target_limit=100000,
|
|
598
598
|
data_references=True,
|
|
@@ -712,6 +712,20 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
712
712
|
if binary is not None and not objects:
|
|
713
713
|
objects = [binary]
|
|
714
714
|
|
|
715
|
+
is_dotnet = (
|
|
716
|
+
isinstance(self.project.loader.main_object, cle.backends.pe.PE)
|
|
717
|
+
and self.project.loader.main_object.is_dotnet
|
|
718
|
+
)
|
|
719
|
+
|
|
720
|
+
if function_prologues is None:
|
|
721
|
+
function_prologues = not is_dotnet
|
|
722
|
+
if is_dotnet and once("dotnet_native"):
|
|
723
|
+
l.warning("You're trying to analyze a .NET binary as native code. Are you sure?")
|
|
724
|
+
if force_smart_scan is None:
|
|
725
|
+
force_smart_scan = not is_dotnet
|
|
726
|
+
if is_dotnet and once("dotnet_native"):
|
|
727
|
+
l.warning("You're trying to analyze a .NET binary as native code. Are you sure?")
|
|
728
|
+
|
|
715
729
|
CFGBase.__init__(
|
|
716
730
|
self,
|
|
717
731
|
"fast",
|
|
@@ -2117,6 +2131,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
2117
2131
|
src_func = self.functions.function(addr=cfg_job.src_node.addr, create=True)
|
|
2118
2132
|
else:
|
|
2119
2133
|
src_func = self.functions.get_by_addr(cfg_job.src_node.addr)
|
|
2134
|
+
assert src_func is not None
|
|
2120
2135
|
if len(src_func.block_addrs_set) <= 1 and src_func.is_default_name:
|
|
2121
2136
|
# assign a name to the caller function that jumps to this procedure
|
|
2122
2137
|
src_func.name = procedure.display_name
|
|
@@ -3843,6 +3858,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
3843
3858
|
|
|
3844
3859
|
for ep in endpoints:
|
|
3845
3860
|
src = self.model.get_any_node(ep.addr)
|
|
3861
|
+
assert src is not None
|
|
3846
3862
|
for rt in return_targets:
|
|
3847
3863
|
if not src.instruction_addrs:
|
|
3848
3864
|
ins_addr = None
|
|
@@ -4333,7 +4349,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
4333
4349
|
|
|
4334
4350
|
# extra check for ARM
|
|
4335
4351
|
if is_arm_arch(self.project.arch) and self._seg_list.occupied_by_sort(addr) == "code":
|
|
4336
|
-
existing_node = self.get_any_node(addr, anyaddr=True)
|
|
4352
|
+
existing_node = self.model.get_any_node(addr, anyaddr=True)
|
|
4337
4353
|
if existing_node is not None and (addr & 1) != (existing_node.addr & 1):
|
|
4338
4354
|
# we are trying to break an existing ARM node with a THUMB node, or vice versa
|
|
4339
4355
|
# this is probably because our current node is unexpected
|
|
@@ -5212,18 +5228,5 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
5212
5228
|
def output(self):
|
|
5213
5229
|
return f"{self._graph.edges(data=True)}"
|
|
5214
5230
|
|
|
5215
|
-
@deprecated(replacement="angr.analyses.CFB")
|
|
5216
|
-
def generate_code_cover(self):
|
|
5217
|
-
"""
|
|
5218
|
-
Generate a list of all recovered basic blocks.
|
|
5219
|
-
"""
|
|
5220
|
-
|
|
5221
|
-
lst = []
|
|
5222
|
-
for cfg_node in self.graph.nodes():
|
|
5223
|
-
size = cfg_node.size
|
|
5224
|
-
lst.append((cfg_node.addr, size))
|
|
5225
|
-
|
|
5226
|
-
return sorted(lst, key=lambda x: x[0])
|
|
5227
|
-
|
|
5228
5231
|
|
|
5229
5232
|
AnalysesHub.register_default("CFGFast", CFGFast)
|
|
@@ -487,7 +487,7 @@ class CFGFastSoot(CFGFast):
|
|
|
487
487
|
# it might be a jumpout
|
|
488
488
|
target_func_addr = None
|
|
489
489
|
if target_addr in self._traced_addresses:
|
|
490
|
-
node = self.get_any_node(target_addr)
|
|
490
|
+
node = self.model.get_any_node(target_addr)
|
|
491
491
|
if node is not None:
|
|
492
492
|
target_func_addr = node.function_address
|
|
493
493
|
if target_func_addr is None:
|
|
@@ -578,7 +578,7 @@ class CFGFastSoot(CFGFast):
|
|
|
578
578
|
if jumpkind == "Ijk_Call" or jumpkind.startswith("Ijk_Sys"):
|
|
579
579
|
function_nodes.add(dst)
|
|
580
580
|
|
|
581
|
-
entry_node = self.get_any_node(self._binary.entry)
|
|
581
|
+
entry_node = self.model.get_any_node(self._binary.entry)
|
|
582
582
|
if entry_node is not None:
|
|
583
583
|
function_nodes.add(entry_node)
|
|
584
584
|
|
|
@@ -616,7 +616,7 @@ class CFGFastSoot(CFGFast):
|
|
|
616
616
|
secondary_function_nodes = set()
|
|
617
617
|
# add all function chunks ("functions" that are not called from anywhere)
|
|
618
618
|
for func_addr in tmp_functions:
|
|
619
|
-
node = self.get_any_node(func_addr)
|
|
619
|
+
node = self.model.get_any_node(func_addr)
|
|
620
620
|
if node is None:
|
|
621
621
|
continue
|
|
622
622
|
if node.addr not in blockaddr_to_function:
|
|
@@ -18,7 +18,7 @@ from angr.sim_type import (
|
|
|
18
18
|
SimTypeFunction,
|
|
19
19
|
SimTypeLongLong,
|
|
20
20
|
)
|
|
21
|
-
from angr.calling_conventions import SimRegArg, SimStackArg, SimCC, SimStructArg, SimComboArg
|
|
21
|
+
from angr.calling_conventions import SimReferenceArgument, SimRegArg, SimStackArg, SimCC, SimStructArg, SimComboArg
|
|
22
22
|
from angr.knowledge_plugins.key_definitions.constants import OP_BEFORE
|
|
23
23
|
from angr.analyses import Analysis, register_analysis
|
|
24
24
|
from angr.analyses.s_reaching_definitions import SRDAView
|
|
@@ -111,10 +111,10 @@ class CallSiteMaker(Analysis):
|
|
|
111
111
|
prototype_libname = func.prototype_libname
|
|
112
112
|
type_collections = []
|
|
113
113
|
if prototype_libname is not None:
|
|
114
|
-
prototype_lib
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
for prototype_lib in SIM_LIBRARIES[prototype_libname]:
|
|
115
|
+
if prototype_lib.type_collection_names:
|
|
116
|
+
for typelib_name in prototype_lib.type_collection_names:
|
|
117
|
+
type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
|
|
118
118
|
if type_collections:
|
|
119
119
|
prototype = dereference_simtype(prototype, type_collections).with_arch( # type: ignore
|
|
120
120
|
self.project.arch
|
|
@@ -144,17 +144,30 @@ class CallSiteMaker(Analysis):
|
|
|
144
144
|
arg_locs = cc.arg_locs(callsite_ty)
|
|
145
145
|
|
|
146
146
|
if arg_locs is not None and cc is not None:
|
|
147
|
-
expanded_arg_locs = []
|
|
147
|
+
expanded_arg_locs: list[SimStackArg | SimRegArg | SimReferenceArgument] = []
|
|
148
148
|
for arg_loc in arg_locs:
|
|
149
149
|
if isinstance(arg_loc, SimComboArg):
|
|
150
150
|
# a ComboArg spans across multiple locations (mostly stack but *in theory* can also be spanning
|
|
151
151
|
# across registers). most importantly, a ComboArg represents one variable, not multiple, but we
|
|
152
152
|
# have no way to know that until later down the pipeline.
|
|
153
153
|
expanded_arg_locs += arg_loc.locations
|
|
154
|
-
|
|
154
|
+
elif isinstance(arg_loc, (SimRegArg, SimStackArg, SimReferenceArgument)):
|
|
155
155
|
expanded_arg_locs.append(arg_loc)
|
|
156
|
+
else:
|
|
157
|
+
raise NotImplementedError("Not implemented yet.")
|
|
156
158
|
|
|
157
159
|
for arg_loc in expanded_arg_locs:
|
|
160
|
+
if isinstance(arg_loc, SimReferenceArgument):
|
|
161
|
+
if not isinstance(arg_loc.ptr_loc, (SimRegArg, SimStackArg)):
|
|
162
|
+
raise NotImplementedError("Why would a calling convention produce this?")
|
|
163
|
+
if isinstance(arg_loc.main_loc, SimStructArg):
|
|
164
|
+
dereference_size = arg_loc.main_loc.struct.size // self.project.arch.byte_width
|
|
165
|
+
else:
|
|
166
|
+
dereference_size = arg_loc.main_loc.size
|
|
167
|
+
arg_loc = arg_loc.ptr_loc
|
|
168
|
+
else:
|
|
169
|
+
dereference_size = None
|
|
170
|
+
|
|
158
171
|
if isinstance(arg_loc, SimRegArg):
|
|
159
172
|
size = arg_loc.size
|
|
160
173
|
offset = arg_loc.check_offset(cc.arch)
|
|
@@ -202,7 +215,7 @@ class CallSiteMaker(Analysis):
|
|
|
202
215
|
vvar_use,
|
|
203
216
|
**vvar_use.tags,
|
|
204
217
|
)
|
|
205
|
-
|
|
218
|
+
arg_expr = vvar_use
|
|
206
219
|
else:
|
|
207
220
|
reg = Expr.Register(
|
|
208
221
|
self._atom_idx(),
|
|
@@ -212,20 +225,17 @@ class CallSiteMaker(Analysis):
|
|
|
212
225
|
reg_name=arg_loc.reg_name,
|
|
213
226
|
ins_addr=last_stmt.ins_addr,
|
|
214
227
|
)
|
|
215
|
-
|
|
228
|
+
arg_expr = reg
|
|
216
229
|
elif isinstance(arg_loc, SimStackArg):
|
|
217
230
|
stack_arg_locs.append(arg_loc)
|
|
218
231
|
_, the_arg = self._resolve_stack_argument(call_stmt, arg_loc)
|
|
219
|
-
|
|
220
|
-
if the_arg is not None:
|
|
221
|
-
args.append(the_arg)
|
|
222
|
-
else:
|
|
223
|
-
args.append(None)
|
|
224
|
-
elif isinstance(arg_loc, SimStructArg):
|
|
225
|
-
l.warning("SimStructArg is not yet supported")
|
|
226
|
-
|
|
232
|
+
arg_expr = the_arg if the_arg is not None else None
|
|
227
233
|
else:
|
|
228
|
-
|
|
234
|
+
assert False, "Unreachable"
|
|
235
|
+
|
|
236
|
+
if arg_expr is not None and dereference_size is not None:
|
|
237
|
+
arg_expr = Expr.Load(self._atom_idx(), arg_expr, dereference_size, endness=archinfo.Endness.BE)
|
|
238
|
+
args.append(arg_expr)
|
|
229
239
|
|
|
230
240
|
# Remove the old call statement
|
|
231
241
|
new_stmts = self.block.statements[:-1]
|
|
@@ -1197,10 +1197,10 @@ class Clinic(Analysis):
|
|
|
1197
1197
|
prototype_libname = func.prototype_libname
|
|
1198
1198
|
type_collections = []
|
|
1199
1199
|
if prototype_libname is not None:
|
|
1200
|
-
prototype_lib
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1200
|
+
for prototype_lib in SIM_LIBRARIES[prototype_libname]:
|
|
1201
|
+
if prototype_lib.type_collection_names:
|
|
1202
|
+
for typelib_name in prototype_lib.type_collection_names:
|
|
1203
|
+
type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
|
|
1204
1204
|
if type_collections:
|
|
1205
1205
|
prototype = dereference_simtype(prototype, type_collections).with_arch( # type: ignore
|
|
1206
1206
|
self.project.arch
|
|
@@ -961,27 +961,6 @@ class ConditionProcessor:
|
|
|
961
961
|
sympy_expr = ConditionProcessor.claripy_ast_to_sympy_expr(cond, memo=memo)
|
|
962
962
|
return ConditionProcessor.sympy_expr_to_claripy_ast(sympy.simplify_logic(sympy_expr, deep=False), memo)
|
|
963
963
|
|
|
964
|
-
@staticmethod
|
|
965
|
-
def simplify_condition_deprecated(cond):
|
|
966
|
-
# Z3's simplification may yield weird and unreadable results
|
|
967
|
-
# hence we mostly rely on our own simplification. we only use Z3's simplification results when it returns a
|
|
968
|
-
# concrete value.
|
|
969
|
-
claripy_simplified = claripy.simplify(cond)
|
|
970
|
-
if not claripy_simplified.symbolic:
|
|
971
|
-
return claripy_simplified
|
|
972
|
-
|
|
973
|
-
simplified = ConditionProcessor._fold_double_negations(cond)
|
|
974
|
-
cond = simplified if simplified is not None else cond
|
|
975
|
-
simplified = ConditionProcessor._revert_short_circuit_conditions(cond)
|
|
976
|
-
cond = simplified if simplified is not None else cond
|
|
977
|
-
simplified = ConditionProcessor._extract_common_subexpressions(cond)
|
|
978
|
-
cond = simplified if simplified is not None else cond
|
|
979
|
-
# simplified = ConditionProcessor._remove_redundant_terms(cond)
|
|
980
|
-
# cond = simplified if simplified is not None else cond
|
|
981
|
-
# in the end, use claripy's simplification to handle really easy cases again
|
|
982
|
-
simplified = ConditionProcessor._simplify_trivial_cases(cond)
|
|
983
|
-
return simplified if simplified is not None else cond
|
|
984
|
-
|
|
985
964
|
@staticmethod
|
|
986
965
|
def _simplify_trivial_cases(cond):
|
|
987
966
|
if cond.op == "And":
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
from typing import TYPE_CHECKING
|
|
3
3
|
|
|
4
4
|
from ailment import Block
|
|
5
|
+
from ailment.statement import Label
|
|
5
6
|
from ailment.block_walker import AILBlockWalkerBase
|
|
6
7
|
|
|
7
8
|
from angr.analyses.decompiler.sequence_walker import SequenceWalker
|
|
@@ -37,8 +38,10 @@ class AILCallCounter(SequenceWalker):
|
|
|
37
38
|
}
|
|
38
39
|
super().__init__(handlers)
|
|
39
40
|
self.calls = 0
|
|
41
|
+
self.non_label_stmts = 0
|
|
40
42
|
|
|
41
43
|
def _handle_Block(self, node: Block, **kwargs): # pylint:disable=unused-argument
|
|
42
44
|
ctr = AILBlockCallCounter()
|
|
43
45
|
ctr.walk(node)
|
|
44
46
|
self.calls += ctr.calls
|
|
47
|
+
self.non_label_stmts += sum(1 for stmt in node.statements if not isinstance(stmt, Label))
|
|
@@ -66,7 +66,7 @@ class PairAILBlockWalker:
|
|
|
66
66
|
def _handle_call_expr(expr_idx: int, expr: Call, stmt_idx: int, stmt: Statement, block_):
|
|
67
67
|
walked_objs[Call].add(expr)
|
|
68
68
|
|
|
69
|
-
_stmt_handlers =
|
|
69
|
+
_stmt_handlers = dict.fromkeys(walked_objs, _handle_ail_obj)
|
|
70
70
|
walker.stmt_handlers = _stmt_handlers
|
|
71
71
|
walker.expr_handlers[Call] = _handle_call_expr
|
|
72
72
|
|
|
@@ -164,6 +164,20 @@ class RemoveRedundantConversions(PeepholeOptimizationExprBase):
|
|
|
164
164
|
**expr.tags,
|
|
165
165
|
)
|
|
166
166
|
|
|
167
|
+
# simpler cases
|
|
168
|
+
# (A & mask) & mask ==> A & mask
|
|
169
|
+
if (
|
|
170
|
+
expr.op == "And"
|
|
171
|
+
and isinstance(expr.operands[1], Const)
|
|
172
|
+
and isinstance(expr.operands[0], BinaryOp)
|
|
173
|
+
and expr.operands[0].op == "And"
|
|
174
|
+
):
|
|
175
|
+
inner_op0, inner_op1 = expr.operands[0].operands
|
|
176
|
+
if (isinstance(inner_op0, Const) and inner_op0.value == expr.operands[1].value) or (
|
|
177
|
+
isinstance(inner_op1, Const) and inner_op1.value == expr.operands[1].value
|
|
178
|
+
):
|
|
179
|
+
return expr.operands[0]
|
|
180
|
+
|
|
167
181
|
return None
|
|
168
182
|
|
|
169
183
|
@staticmethod
|
|
@@ -1281,11 +1281,11 @@ class CFunctionCall(CStatement, CExpression):
|
|
|
1281
1281
|
if self.callee_func.prototype_libname is not None:
|
|
1282
1282
|
# we need to deref the prototype in case it uses SimTypeRef internally
|
|
1283
1283
|
type_collections = []
|
|
1284
|
-
prototype_lib
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1284
|
+
for prototype_lib in SIM_LIBRARIES[self.callee_func.prototype_libname]:
|
|
1285
|
+
if prototype_lib.type_collection_names:
|
|
1286
|
+
for typelib_name in prototype_lib.type_collection_names:
|
|
1287
|
+
type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
|
|
1288
|
+
proto = dereference_simtype(proto, type_collections)
|
|
1289
1289
|
return proto
|
|
1290
1290
|
returnty = SimTypeInt(signed=False)
|
|
1291
1291
|
return SimTypeFunction([arg.type for arg in self.args], returnty).with_arch(self.codegen.project.arch)
|
|
@@ -90,6 +90,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
90
90
|
parent_region=None,
|
|
91
91
|
improve_algorithm=False,
|
|
92
92
|
use_multistmtexprs: MultiStmtExprMode = MultiStmtExprMode.MAX_ONE_CALL,
|
|
93
|
+
multistmtexpr_stmt_threshold: int = 5,
|
|
93
94
|
**kwargs,
|
|
94
95
|
):
|
|
95
96
|
super().__init__(
|
|
@@ -126,6 +127,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
126
127
|
self._edge_virtualization_hints = []
|
|
127
128
|
|
|
128
129
|
self._use_multistmtexprs = use_multistmtexprs
|
|
130
|
+
self._multistmtexpr_stmt_threshold = multistmtexpr_stmt_threshold
|
|
129
131
|
self._analyze()
|
|
130
132
|
|
|
131
133
|
@staticmethod
|
|
@@ -540,7 +542,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
540
542
|
):
|
|
541
543
|
stmts = self._build_multistatementexpr_statements(succ)
|
|
542
544
|
assert stmts is not None
|
|
543
|
-
if
|
|
545
|
+
if (
|
|
546
|
+
stmts
|
|
547
|
+
and sum(1 for stmt in stmts if not isinstance(stmt, Label))
|
|
548
|
+
<= self._multistmtexpr_stmt_threshold
|
|
549
|
+
):
|
|
544
550
|
edge_cond_succhead = MultiStatementExpression(
|
|
545
551
|
None,
|
|
546
552
|
stmts,
|
|
@@ -2612,12 +2618,14 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2612
2618
|
if self._use_multistmtexprs == MultiStmtExprMode.NEVER:
|
|
2613
2619
|
return False
|
|
2614
2620
|
if self._use_multistmtexprs == MultiStmtExprMode.ALWAYS:
|
|
2615
|
-
|
|
2621
|
+
ctr = AILCallCounter()
|
|
2622
|
+
ctr.walk(node)
|
|
2623
|
+
return ctr.non_label_stmts <= self._multistmtexpr_stmt_threshold
|
|
2616
2624
|
if self._use_multistmtexprs == MultiStmtExprMode.MAX_ONE_CALL:
|
|
2617
2625
|
# count the number of calls
|
|
2618
2626
|
ctr = AILCallCounter()
|
|
2619
2627
|
ctr.walk(node)
|
|
2620
|
-
return ctr.calls <= 1
|
|
2628
|
+
return ctr.calls <= 1 and ctr.non_label_stmts <= self._multistmtexpr_stmt_threshold
|
|
2621
2629
|
l.warning("Unsupported enum value for _use_multistmtexprs: %s", self._use_multistmtexprs)
|
|
2622
2630
|
return False
|
|
2623
2631
|
|
|
@@ -315,7 +315,11 @@ class APIObfuscationFinder(Analysis):
|
|
|
315
315
|
|
|
316
316
|
@staticmethod
|
|
317
317
|
def is_apiname(name: str) -> bool:
|
|
318
|
-
return any(
|
|
318
|
+
return any(
|
|
319
|
+
not isinstance(lib, SimSyscallLibrary) and lib.has_prototype(name)
|
|
320
|
+
for libs in SIM_LIBRARIES.values()
|
|
321
|
+
for lib in libs
|
|
322
|
+
)
|
|
319
323
|
|
|
320
324
|
|
|
321
325
|
AnalysesHub.register_default("APIObfuscationFinder", APIObfuscationFinder)
|
|
@@ -30,7 +30,7 @@ class APIObfType1PeepholeOptimizer(PeepholeOptimizationExprBase):
|
|
|
30
30
|
# assign a new function on-demand
|
|
31
31
|
symbol = self.project.loader.extern_object.make_extern(funcname)
|
|
32
32
|
hook_addr = self.project.hook_symbol(
|
|
33
|
-
symbol.rebased_addr, SIM_LIBRARIES["linux"].get_stub(funcname, self.project.arch)
|
|
33
|
+
symbol.rebased_addr, SIM_LIBRARIES["linux"][0].get_stub(funcname, self.project.arch)
|
|
34
34
|
)
|
|
35
35
|
func = self.kb.functions.function(addr=hook_addr, name=funcname, create=True)
|
|
36
36
|
func.is_simprocedure = True
|