angr 9.2.147__py3-none-win_amd64.whl → 9.2.149__py3-none-win_amd64.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/calling_convention.py +42 -2
- 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 +17 -14
- angr/analyses/cfg/cfg_fast.py +68 -63
- angr/analyses/cfg/cfg_fast_soot.py +3 -3
- angr/analyses/decompiler/ail_simplifier.py +65 -32
- angr/analyses/decompiler/block_simplifier.py +20 -6
- angr/analyses/decompiler/callsite_maker.py +28 -18
- angr/analyses/decompiler/clinic.py +84 -17
- angr/analyses/decompiler/condition_processor.py +0 -21
- angr/analyses/decompiler/counters/call_counter.py +3 -0
- angr/analyses/decompiler/dephication/rewriting_engine.py +24 -2
- angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
- angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +15 -13
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +1 -1
- angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
- angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +165 -0
- angr/analyses/decompiler/optimization_passes/engine_base.py +11 -2
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +17 -2
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +10 -6
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +99 -30
- angr/analyses/decompiler/peephole_optimizations/__init__.py +6 -0
- angr/analyses/decompiler/peephole_optimizations/base.py +43 -3
- angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +3 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +4 -1
- angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +69 -2
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +14 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
- angr/analyses/decompiler/presets/fast.py +2 -0
- angr/analyses/decompiler/presets/full.py +2 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +51 -4
- angr/analyses/decompiler/ssailification/ssailification.py +23 -3
- angr/analyses/decompiler/ssailification/traversal_engine.py +15 -1
- angr/analyses/decompiler/structured_codegen/c.py +146 -15
- angr/analyses/decompiler/structuring/phoenix.py +11 -3
- angr/analyses/decompiler/utils.py +6 -1
- 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/s_reaching_definitions/s_rda_view.py +1 -0
- angr/analyses/stack_pointer_tracker.py +1 -1
- angr/analyses/static_hooker.py +11 -9
- angr/analyses/typehoon/lifter.py +20 -0
- angr/analyses/typehoon/simple_solver.py +42 -9
- angr/analyses/typehoon/translator.py +4 -1
- angr/analyses/typehoon/typeconsts.py +17 -6
- angr/analyses/typehoon/typehoon.py +21 -5
- angr/analyses/variable_recovery/engine_ail.py +52 -13
- angr/analyses/variable_recovery/engine_base.py +37 -12
- angr/analyses/variable_recovery/variable_recovery_fast.py +33 -2
- angr/calling_conventions.py +96 -27
- angr/engines/light/engine.py +7 -0
- angr/exploration_techniques/director.py +1 -1
- angr/knowledge_plugins/functions/function.py +109 -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/knowledge_plugins/propagations/states.py +5 -2
- angr/knowledge_plugins/variables/variable_manager.py +3 -3
- angr/lib/angr_native.dll +0 -0
- angr/procedures/definitions/__init__.py +15 -12
- angr/procedures/definitions/types_stl.py +22 -0
- 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 +251 -146
- 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.149.dist-info}/METADATA +9 -8
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/RECORD +91 -85
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/WHEEL +1 -1
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info/licenses}/LICENSE +3 -0
- {angr-9.2.147.dist-info → angr-9.2.149.dist-info}/entry_points.txt +0 -0
- {angr-9.2.147.dist-info → angr-9.2.149.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):
|
|
@@ -13,8 +13,16 @@ import ailment
|
|
|
13
13
|
|
|
14
14
|
from angr.code_location import ExternalCodeLocation
|
|
15
15
|
|
|
16
|
-
from angr.calling_conventions import
|
|
16
|
+
from angr.calling_conventions import (
|
|
17
|
+
SimFunctionArgument,
|
|
18
|
+
SimRegArg,
|
|
19
|
+
SimStackArg,
|
|
20
|
+
SimCC,
|
|
21
|
+
default_cc,
|
|
22
|
+
SimCCMicrosoftThiscall,
|
|
23
|
+
)
|
|
17
24
|
from angr.sim_type import (
|
|
25
|
+
SimTypeCppFunction,
|
|
18
26
|
SimTypeInt,
|
|
19
27
|
SimTypeFunction,
|
|
20
28
|
SimType,
|
|
@@ -24,6 +32,7 @@ from angr.sim_type import (
|
|
|
24
32
|
SimTypeBottom,
|
|
25
33
|
SimTypeFloat,
|
|
26
34
|
SimTypeDouble,
|
|
35
|
+
parse_cpp_file,
|
|
27
36
|
)
|
|
28
37
|
from angr.sim_variable import SimStackVariable, SimRegisterVariable
|
|
29
38
|
from angr.knowledge_plugins.key_definitions.atoms import Register, MemoryLocation, SpOffset
|
|
@@ -153,6 +162,13 @@ class CallingConventionAnalysis(Analysis):
|
|
|
153
162
|
|
|
154
163
|
assert self._function is not None
|
|
155
164
|
|
|
165
|
+
demangled_name = self._function.demangled_name
|
|
166
|
+
if demangled_name != self._function.name:
|
|
167
|
+
r_demangled = self._analyze_demangled_name(demangled_name)
|
|
168
|
+
if r_demangled is not None:
|
|
169
|
+
self.cc, self.prototype, self.prototype_libname = r_demangled
|
|
170
|
+
return
|
|
171
|
+
|
|
156
172
|
if self._function.is_simprocedure:
|
|
157
173
|
hooker = self.project.hooked_by(self._function.addr)
|
|
158
174
|
if isinstance(
|
|
@@ -348,6 +364,30 @@ class CallingConventionAnalysis(Analysis):
|
|
|
348
364
|
|
|
349
365
|
return None
|
|
350
366
|
|
|
367
|
+
def _analyze_demangled_name(self, name: str) -> tuple[SimCC, SimTypeFunction, str | None] | None:
|
|
368
|
+
"""
|
|
369
|
+
Analyze a function with a demangled name. Only C++ names are supported for now.
|
|
370
|
+
|
|
371
|
+
:param name: The demangled name of the function.
|
|
372
|
+
:return: A tuple of the calling convention, the function type, and the library name if available.
|
|
373
|
+
"""
|
|
374
|
+
parsed, _ = parse_cpp_file(name)
|
|
375
|
+
if not parsed or len(parsed) != 1:
|
|
376
|
+
return None
|
|
377
|
+
proto = next(iter(parsed.values()))
|
|
378
|
+
if (
|
|
379
|
+
isinstance(proto, SimTypeCppFunction)
|
|
380
|
+
and self.project.simos.name == "Win32"
|
|
381
|
+
and self.project.arch.name == "X86"
|
|
382
|
+
and proto.convention == "__thiscall"
|
|
383
|
+
):
|
|
384
|
+
cc_cls = SimCCMicrosoftThiscall
|
|
385
|
+
else:
|
|
386
|
+
cc_cls = default_cc(self.project.arch.name, self.project.simos.name)
|
|
387
|
+
assert cc_cls is not None
|
|
388
|
+
cc = cc_cls(self.project.arch)
|
|
389
|
+
return cc, proto, None
|
|
390
|
+
|
|
351
391
|
def _analyze_function(self) -> tuple[SimCC, SimTypeFunction] | None:
|
|
352
392
|
"""
|
|
353
393
|
Go over the variable information in variable manager for this function, and return all uninitialized
|
|
@@ -681,7 +721,7 @@ class CallingConventionAnalysis(Analysis):
|
|
|
681
721
|
# no more arguments
|
|
682
722
|
temp_args.append(None)
|
|
683
723
|
elif isinstance(arg_loc, SimStackArg):
|
|
684
|
-
if arg_loc.stack_offset in defs_by_stack_offset:
|
|
724
|
+
if arg_loc.stack_offset - cc.STACKARG_SP_DIFF in defs_by_stack_offset:
|
|
685
725
|
temp_args.append(arg_loc)
|
|
686
726
|
else:
|
|
687
727
|
# no more arguments
|
|
@@ -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
|
|
@@ -2967,10 +2967,13 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
2967
2967
|
new_state.options.add(o.DO_RET_EMULATION)
|
|
2968
2968
|
# Remove bad constraints
|
|
2969
2969
|
# FIXME: This is so hackish...
|
|
2970
|
-
|
|
2970
|
+
preserved_constraints = [
|
|
2971
2971
|
c for c in new_state.solver.constraints if c.op != "BoolV" or c.args[0] is not False
|
|
2972
2972
|
]
|
|
2973
|
-
new_state.solver._solver.
|
|
2973
|
+
new_solver = new_state.solver._solver.blank_copy()
|
|
2974
|
+
new_solver.add(preserved_constraints)
|
|
2975
|
+
new_state.solver._stored_solver = new_solver
|
|
2976
|
+
|
|
2974
2977
|
# Swap them
|
|
2975
2978
|
saved_state, job.state = job.state, new_state
|
|
2976
2979
|
sim_successors, exception_info, _ = self._get_simsuccessors(addr, job)
|
|
@@ -3376,9 +3379,9 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
3376
3379
|
|
|
3377
3380
|
all_predecessors = []
|
|
3378
3381
|
|
|
3379
|
-
nodes = self.get_all_nodes(function_address)
|
|
3382
|
+
nodes = self.model.get_all_nodes(function_address)
|
|
3380
3383
|
for n in nodes:
|
|
3381
|
-
predecessors = list(self.get_predecessors(n))
|
|
3384
|
+
predecessors = list(self.model.get_predecessors(n))
|
|
3382
3385
|
all_predecessors.extend(predecessors)
|
|
3383
3386
|
|
|
3384
3387
|
return all_predecessors
|
|
@@ -3391,8 +3394,8 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
3391
3394
|
Return: a list of lists of nodes representing paths.
|
|
3392
3395
|
"""
|
|
3393
3396
|
if isinstance(begin, int) and isinstance(end, int):
|
|
3394
|
-
n_begin = self.get_any_node(begin)
|
|
3395
|
-
n_end = self.get_any_node(end)
|
|
3397
|
+
n_begin = self.model.get_any_node(begin)
|
|
3398
|
+
n_end = self.model.get_any_node(end)
|
|
3396
3399
|
|
|
3397
3400
|
elif isinstance(begin, CFGENode) and isinstance(end, CFGENode):
|
|
3398
3401
|
n_begin = begin
|
|
@@ -3417,7 +3420,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
3417
3420
|
|
|
3418
3421
|
for ep in self._entry_points:
|
|
3419
3422
|
# FIXME: This is not always correct. We'd better store CFGNodes in self._entry_points
|
|
3420
|
-
ep_node = self.get_any_node(ep)
|
|
3423
|
+
ep_node = self.model.get_any_node(ep)
|
|
3421
3424
|
|
|
3422
3425
|
if not ep_node:
|
|
3423
3426
|
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
|
|
@@ -4825,66 +4841,68 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
4825
4841
|
|
|
4826
4842
|
# determine if the function uses ebp as a general purpose register or not
|
|
4827
4843
|
if addr == func_addr or 0 < addr - func_addr <= 0x20:
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
and len(insn.operands) == 2
|
|
4834
|
-
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4835
|
-
and insn.operands[1].type == capstone.x86.X86_OP_REG
|
|
4836
|
-
):
|
|
4844
|
+
func = self.kb.functions.get_by_addr(func_addr)
|
|
4845
|
+
if "bp_as_gpr" not in func.info:
|
|
4846
|
+
ebp_as_gpr = True
|
|
4847
|
+
cap = self._lift(addr, size=cfg_node.size).capstone
|
|
4848
|
+
for insn in cap.insns:
|
|
4837
4849
|
if (
|
|
4850
|
+
insn.mnemonic == "mov"
|
|
4851
|
+
and len(insn.operands) == 2
|
|
4852
|
+
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4853
|
+
and insn.operands[1].type == capstone.x86.X86_OP_REG
|
|
4854
|
+
):
|
|
4855
|
+
if (
|
|
4856
|
+
insn.operands[0].reg == capstone.x86.X86_REG_EBP
|
|
4857
|
+
and insn.operands[1].reg == capstone.x86.X86_REG_ESP
|
|
4858
|
+
):
|
|
4859
|
+
ebp_as_gpr = False
|
|
4860
|
+
break
|
|
4861
|
+
elif (
|
|
4862
|
+
insn.mnemonic == "lea"
|
|
4863
|
+
and len(insn.operands) == 2
|
|
4864
|
+
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4865
|
+
and insn.operands[1].type == capstone.x86.X86_OP_MEM
|
|
4866
|
+
) and (
|
|
4838
4867
|
insn.operands[0].reg == capstone.x86.X86_REG_EBP
|
|
4839
|
-
and insn.operands[1].
|
|
4868
|
+
and insn.operands[1].mem.base == capstone.x86.X86_REG_ESP
|
|
4840
4869
|
):
|
|
4841
4870
|
ebp_as_gpr = False
|
|
4842
4871
|
break
|
|
4843
|
-
|
|
4844
|
-
insn.mnemonic == "lea"
|
|
4845
|
-
and len(insn.operands) == 2
|
|
4846
|
-
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4847
|
-
and insn.operands[1].type == capstone.x86.X86_OP_MEM
|
|
4848
|
-
) and (
|
|
4849
|
-
insn.operands[0].reg == capstone.x86.X86_REG_EBP
|
|
4850
|
-
and insn.operands[1].mem.base == capstone.x86.X86_REG_ESP
|
|
4851
|
-
):
|
|
4852
|
-
ebp_as_gpr = False
|
|
4853
|
-
break
|
|
4854
|
-
func = self.kb.functions.get_by_addr(func_addr)
|
|
4855
|
-
func.info["bp_as_gpr"] = ebp_as_gpr
|
|
4872
|
+
func.info["bp_as_gpr"] = ebp_as_gpr
|
|
4856
4873
|
|
|
4857
4874
|
elif self.project.arch.name == "AMD64":
|
|
4858
4875
|
# determine if the function uses rbp as a general purpose register or not
|
|
4859
4876
|
if addr == func_addr or 0 < addr - func_addr <= 0x20:
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
and len(insn.operands) == 2
|
|
4866
|
-
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4867
|
-
and insn.operands[1].type == capstone.x86.X86_OP_REG
|
|
4868
|
-
):
|
|
4877
|
+
func = self.kb.functions.get_by_addr(func_addr)
|
|
4878
|
+
if "bp_as_gpr" not in func.info:
|
|
4879
|
+
rbp_as_gpr = True
|
|
4880
|
+
cap = self._lift(addr, size=cfg_node.size).capstone
|
|
4881
|
+
for insn in cap.insns:
|
|
4869
4882
|
if (
|
|
4883
|
+
insn.mnemonic == "mov"
|
|
4884
|
+
and len(insn.operands) == 2
|
|
4885
|
+
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4886
|
+
and insn.operands[1].type == capstone.x86.X86_OP_REG
|
|
4887
|
+
):
|
|
4888
|
+
if (
|
|
4889
|
+
insn.operands[0].reg == capstone.x86.X86_REG_RBP
|
|
4890
|
+
and insn.operands[1].reg == capstone.x86.X86_REG_RSP
|
|
4891
|
+
):
|
|
4892
|
+
rbp_as_gpr = False
|
|
4893
|
+
break
|
|
4894
|
+
elif (
|
|
4895
|
+
insn.mnemonic == "lea"
|
|
4896
|
+
and len(insn.operands) == 2
|
|
4897
|
+
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4898
|
+
and insn.operands[1].type == capstone.x86.X86_OP_MEM
|
|
4899
|
+
) and (
|
|
4870
4900
|
insn.operands[0].reg == capstone.x86.X86_REG_RBP
|
|
4871
|
-
and insn.operands[1].
|
|
4901
|
+
and insn.operands[1].mem.base == capstone.x86.X86_REG_RSP
|
|
4872
4902
|
):
|
|
4873
4903
|
rbp_as_gpr = False
|
|
4874
4904
|
break
|
|
4875
|
-
|
|
4876
|
-
insn.mnemonic == "lea"
|
|
4877
|
-
and len(insn.operands) == 2
|
|
4878
|
-
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4879
|
-
and insn.operands[1].type == capstone.x86.X86_OP_MEM
|
|
4880
|
-
) and (
|
|
4881
|
-
insn.operands[0].reg == capstone.x86.X86_REG_RBP
|
|
4882
|
-
and insn.operands[1].mem.base == capstone.x86.X86_REG_RSP
|
|
4883
|
-
):
|
|
4884
|
-
rbp_as_gpr = False
|
|
4885
|
-
break
|
|
4886
|
-
func = self.kb.functions.get_by_addr(func_addr)
|
|
4887
|
-
func.info["bp_as_gpr"] = rbp_as_gpr
|
|
4905
|
+
func.info["bp_as_gpr"] = rbp_as_gpr
|
|
4888
4906
|
|
|
4889
4907
|
def _extract_node_cluster_by_dependency(self, addr, include_successors=False) -> set[int]:
|
|
4890
4908
|
to_remove = {addr}
|
|
@@ -5212,18 +5230,5 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
5212
5230
|
def output(self):
|
|
5213
5231
|
return f"{self._graph.edges(data=True)}"
|
|
5214
5232
|
|
|
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
5233
|
|
|
5229
5234
|
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:
|