angr 9.2.87__py3-none-manylinux2014_x86_64.whl → 9.2.89__py3-none-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +4 -1
- angr/analyses/decompiler/clinic.py +16 -0
- angr/analyses/decompiler/decompiler.py +3 -0
- angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
- angr/analyses/decompiler/optimization_passes/cross_jump_reverter.py +108 -0
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +17 -4
- angr/analyses/decompiler/optimization_passes/return_duplicator.py +4 -32
- angr/analyses/decompiler/structured_codegen/c.py +12 -2
- angr/analyses/decompiler/utils.py +13 -0
- angr/analyses/typehoon/dfa.py +108 -0
- angr/analyses/typehoon/lifter.py +34 -2
- angr/analyses/typehoon/simple_solver.py +1043 -503
- angr/analyses/typehoon/translator.py +13 -4
- angr/analyses/typehoon/typeconsts.py +117 -36
- angr/analyses/typehoon/typehoon.py +31 -11
- angr/analyses/typehoon/typevars.py +88 -21
- angr/analyses/typehoon/variance.py +10 -0
- angr/analyses/variable_recovery/engine_ail.py +28 -9
- angr/analyses/variable_recovery/engine_base.py +50 -43
- angr/analyses/variable_recovery/variable_recovery_base.py +16 -3
- angr/analyses/variable_recovery/variable_recovery_fast.py +14 -5
- angr/exploration_techniques/tracer.py +2 -0
- angr/misc/autoimport.py +26 -0
- angr/procedures/definitions/__init__.py +32 -3
- angr/utils/constants.py +1 -0
- angr/utils/graph.py +20 -1
- {angr-9.2.87.dist-info → angr-9.2.89.dist-info}/METADATA +7 -6
- {angr-9.2.87.dist-info → angr-9.2.89.dist-info}/RECORD +32 -244
- angr-9.2.89.dist-info/top_level.txt +1 -0
- angr/procedures/definitions/ntdll.py +0 -12
- angr-9.2.87.dist-info/top_level.txt +0 -2
- tests/__init__.py +0 -0
- tests/analyses/__init__.py +0 -0
- tests/analyses/cfg/__init__.py +0 -0
- tests/analyses/cfg/test_cfg_clflush.py +0 -43
- tests/analyses/cfg/test_cfg_get_any_node.py +0 -34
- tests/analyses/cfg/test_cfg_manager.py +0 -32
- tests/analyses/cfg/test_cfg_model.py +0 -55
- tests/analyses/cfg/test_cfg_patching.py +0 -378
- tests/analyses/cfg/test_cfg_rust_got_resolution.py +0 -36
- tests/analyses/cfg/test_cfg_thumb_firmware.py +0 -50
- tests/analyses/cfg/test_cfg_vex_postprocessor.py +0 -27
- tests/analyses/cfg/test_cfgemulated.py +0 -634
- tests/analyses/cfg/test_cfgfast.py +0 -1123
- tests/analyses/cfg/test_cfgfast_soot.py +0 -38
- tests/analyses/cfg/test_const_resolver.py +0 -38
- tests/analyses/cfg/test_iat_resolver.py +0 -37
- tests/analyses/cfg/test_jumptables.py +0 -3008
- tests/analyses/cfg/test_noop_blocks.py +0 -54
- tests/analyses/cfg_slice_to_sink/__init__.py +0 -0
- tests/analyses/cfg_slice_to_sink/test_cfg_slice_to_sink.py +0 -93
- tests/analyses/cfg_slice_to_sink/test_graph.py +0 -114
- tests/analyses/cfg_slice_to_sink/test_transitions.py +0 -28
- tests/analyses/decompiler/__init__.py +0 -0
- tests/analyses/decompiler/test_baseptr_save_simplifier.py +0 -80
- tests/analyses/decompiler/test_decompiler.py +0 -3336
- tests/analyses/decompiler/test_peephole_optimizations.py +0 -48
- tests/analyses/decompiler/test_propagator_loops.py +0 -101
- tests/analyses/decompiler/test_structurer.py +0 -275
- tests/analyses/reaching_definitions/__init__.py +0 -0
- tests/analyses/reaching_definitions/test_dep_graph.py +0 -432
- tests/analyses/reaching_definitions/test_function_handler.py +0 -131
- tests/analyses/reaching_definitions/test_heap_allocator.py +0 -46
- tests/analyses/reaching_definitions/test_rd_state.py +0 -78
- tests/analyses/reaching_definitions/test_reachingdefinitions.py +0 -463
- tests/analyses/reaching_definitions/test_subject.py +0 -76
- tests/analyses/test_bindiff.py +0 -52
- tests/analyses/test_block_simplifier.py +0 -112
- tests/analyses/test_boyscout.py +0 -104
- tests/analyses/test_calling_convention_analysis.py +0 -352
- tests/analyses/test_callsite_maker.py +0 -60
- tests/analyses/test_cdg.py +0 -165
- tests/analyses/test_cfb.py +0 -37
- tests/analyses/test_class_identifier.py +0 -46
- tests/analyses/test_clinic.py +0 -30
- tests/analyses/test_codetagging.py +0 -32
- tests/analyses/test_constantpropagation.py +0 -88
- tests/analyses/test_ddg.py +0 -95
- tests/analyses/test_ddg_global_var_dependencies.py +0 -83
- tests/analyses/test_ddg_memvar_addresses.py +0 -40
- tests/analyses/test_disassembly.py +0 -121
- tests/analyses/test_find_objects_static.py +0 -35
- tests/analyses/test_flirt.py +0 -49
- tests/analyses/test_identifier.py +0 -33
- tests/analyses/test_init_finder.py +0 -38
- tests/analyses/test_proximitygraph.py +0 -31
- tests/analyses/test_reassembler.py +0 -295
- tests/analyses/test_regionidentifier.py +0 -27
- tests/analyses/test_slicing.py +0 -164
- tests/analyses/test_stack_pointer_tracker.py +0 -74
- tests/analyses/test_static_hooker.py +0 -28
- tests/analyses/test_typehoon.py +0 -55
- tests/analyses/test_variablerecovery.py +0 -464
- tests/analyses/test_vfg.py +0 -221
- tests/analyses/test_vtable.py +0 -31
- tests/analyses/test_xrefs.py +0 -77
- tests/common.py +0 -128
- tests/engines/__init__.py +0 -0
- tests/engines/light/__init__.py +0 -0
- tests/engines/light/test_data.py +0 -17
- tests/engines/pcode/__init__.py +0 -0
- tests/engines/pcode/test_emulate.py +0 -607
- tests/engines/pcode/test_pcode.py +0 -84
- tests/engines/test_actions.py +0 -27
- tests/engines/test_hook.py +0 -112
- tests/engines/test_java.py +0 -697
- tests/engines/test_unicorn.py +0 -518
- tests/engines/vex/__init__.py +0 -0
- tests/engines/vex/test_lifter.py +0 -124
- tests/engines/vex/test_vex.py +0 -574
- tests/exploration_techniques/__init__.py +0 -0
- tests/exploration_techniques/test_cacher.py +0 -45
- tests/exploration_techniques/test_director.py +0 -67
- tests/exploration_techniques/test_driller_core.py +0 -48
- tests/exploration_techniques/test_loop_seer.py +0 -158
- tests/exploration_techniques/test_memory_watcher.py +0 -46
- tests/exploration_techniques/test_oppologist.py +0 -65
- tests/exploration_techniques/test_spiller.py +0 -82
- tests/exploration_techniques/test_stochastic.py +0 -40
- tests/exploration_techniques/test_tech_builder.py +0 -61
- tests/exploration_techniques/test_tracer.py +0 -856
- tests/exploration_techniques/test_unique.py +0 -40
- tests/exploration_techniques/test_veritesting.py +0 -120
- tests/factory/__init__.py +0 -0
- tests/factory/block/__init__.py +0 -0
- tests/factory/block/test_block_cache.py +0 -33
- tests/factory/block/test_keystone.py +0 -106
- tests/factory/test_argc.py +0 -101
- tests/factory/test_argc_sym.py +0 -110
- tests/factory/test_argv.py +0 -158
- tests/factory/test_callable.py +0 -266
- tests/factory/test_windows_args.py +0 -36
- tests/knowledge_plugins/__init__.py +0 -0
- tests/knowledge_plugins/cfg/__init__.py +0 -0
- tests/knowledge_plugins/cfg/test_cfg_manager.py +0 -36
- tests/knowledge_plugins/functions/__init__.py +0 -0
- tests/knowledge_plugins/functions/test_function.py +0 -91
- tests/knowledge_plugins/functions/test_function2.py +0 -79
- tests/knowledge_plugins/functions/test_function_manager.py +0 -139
- tests/knowledge_plugins/functions/test_prototypes.py +0 -53
- tests/knowledge_plugins/key_definitions/__init__.py +0 -0
- tests/knowledge_plugins/key_definitions/test_atoms.py +0 -24
- tests/knowledge_plugins/key_definitions/test_environment.py +0 -126
- tests/knowledge_plugins/key_definitions/test_heap_address.py +0 -27
- tests/knowledge_plugins/key_definitions/test_live_definitions.py +0 -72
- tests/knowledge_plugins/test_dwarf_variables.py +0 -240
- tests/knowledge_plugins/test_kb_plugins.py +0 -91
- tests/knowledge_plugins/test_kb_plugins_dwarf.py +0 -36
- tests/knowledge_plugins/test_patches.py +0 -48
- tests/misc/__init__.py +0 -0
- tests/misc/test_hookset.py +0 -57
- tests/perf/__init__.py +0 -0
- tests/perf/perf_cfgemulated.py +0 -19
- tests/perf/perf_cfgfast.py +0 -18
- tests/perf/perf_concrete_execution.py +0 -41
- tests/perf/perf_siminspect_nop.py +0 -36
- tests/perf/perf_state_copy.py +0 -33
- tests/perf/perf_unicorn_0.py +0 -27
- tests/perf/perf_unicorn_1.py +0 -23
- tests/procedures/__init__.py +0 -0
- tests/procedures/glibc/__init__.py +0 -0
- tests/procedures/glibc/test_ctype_locale.py +0 -164
- tests/procedures/libc/__init__.py +0 -0
- tests/procedures/libc/test_fgets.py +0 -53
- tests/procedures/libc/test_scanf.py +0 -205
- tests/procedures/libc/test_sprintf.py +0 -44
- tests/procedures/libc/test_sscanf.py +0 -63
- tests/procedures/libc/test_strcasecmp.py +0 -37
- tests/procedures/libc/test_string.py +0 -1102
- tests/procedures/libc/test_strtol.py +0 -78
- tests/procedures/linux_kernel/__init__.py +0 -0
- tests/procedures/linux_kernel/test_lseek.py +0 -174
- tests/procedures/posix/__init__.py +0 -0
- tests/procedures/posix/test_chroot.py +0 -33
- tests/procedures/posix/test_getenv.py +0 -78
- tests/procedures/posix/test_pwrite_pread.py +0 -57
- tests/procedures/posix/test_sim_time.py +0 -46
- tests/procedures/posix/test_unlink.py +0 -46
- tests/procedures/test_project_resolve_simproc.py +0 -43
- tests/procedures/test_sim_procedure.py +0 -117
- tests/procedures/test_stub_procedure_args.py +0 -53
- tests/serialization/__init__.py +0 -0
- tests/serialization/test_db.py +0 -197
- tests/serialization/test_pickle.py +0 -95
- tests/serialization/test_serialization.py +0 -132
- tests/serialization/test_vault.py +0 -169
- tests/sim/__init__.py +0 -3
- tests/sim/exec_func/__init__.py +0 -0
- tests/sim/exec_func/test_mem_funcs.py +0 -55
- tests/sim/exec_func/test_str_funcs.py +0 -93
- tests/sim/exec_func/test_syscall_result.py +0 -39
- tests/sim/exec_insn/__init__.py +0 -0
- tests/sim/exec_insn/test_adc.py +0 -44
- tests/sim/exec_insn/test_ops.py +0 -83
- tests/sim/exec_insn/test_rcr.py +0 -26
- tests/sim/exec_insn/test_rol.py +0 -51
- tests/sim/exec_insn/test_signed_div.py +0 -34
- tests/sim/exec_insn/test_sqrt.py +0 -56
- tests/sim/options/__init__.py +0 -0
- tests/sim/options/test_0div.py +0 -54
- tests/sim/options/test_symbolic_fd.py +0 -59
- tests/sim/options/test_unsupported.py +0 -34
- tests/sim/test_accuracy.py +0 -137
- tests/sim/test_checkbyte.py +0 -53
- tests/sim/test_echo.py +0 -36
- tests/sim/test_fauxware.py +0 -202
- tests/sim/test_self_modifying_code.py +0 -65
- tests/sim/test_simple_api.py +0 -36
- tests/sim/test_simulation_manager.py +0 -147
- tests/sim/test_stack_alignment.py +0 -65
- tests/sim/test_state.py +0 -303
- tests/sim/test_state_customization.py +0 -54
- tests/sim/test_symbol_hooked_by.py +0 -49
- tests/simos/__init__.py +0 -0
- tests/simos/windows/__init__.py +0 -0
- tests/simos/windows/test_windows_stack_cookie.py +0 -58
- tests/state_plugins/__init__.py +0 -0
- tests/state_plugins/inspect/__init__.py +0 -0
- tests/state_plugins/inspect/test_inspect.py +0 -310
- tests/state_plugins/inspect/test_syscall_override.py +0 -90
- tests/state_plugins/posix/__init__.py +0 -0
- tests/state_plugins/posix/test_file_struct_funcs.py +0 -56
- tests/state_plugins/posix/test_files.py +0 -69
- tests/state_plugins/posix/test_posix.py +0 -72
- tests/state_plugins/solver/__init__.py +0 -0
- tests/state_plugins/solver/test_simsolver.py +0 -58
- tests/state_plugins/solver/test_symbolic.py +0 -153
- tests/state_plugins/solver/test_variable_registration.py +0 -46
- tests/state_plugins/test_callstack.py +0 -54
- tests/state_plugins/test_gdb_plugin.py +0 -35
- tests/state_plugins/test_multi_open_file.py +0 -47
- tests/state_plugins/test_symbolization.py +0 -38
- tests/storage/__init__.py +0 -0
- tests/storage/test_memory.py +0 -960
- tests/storage/test_memory_merge.py +0 -114
- tests/storage/test_memview.py +0 -205
- tests/storage/test_mmap.py +0 -26
- tests/storage/test_multivalues.py +0 -44
- tests/storage/test_permissions.py +0 -32
- tests/storage/test_ptmalloc.py +0 -291
- tests/storage/test_relro_perm.py +0 -49
- tests/test_calling_conventions.py +0 -86
- tests/test_types.py +0 -329
- tests/utils/__init__.py +0 -0
- tests/utils/test_graph.py +0 -41
- {angr-9.2.87.dist-info → angr-9.2.89.dist-info}/LICENSE +0 -0
- {angr-9.2.87.dist-info → angr-9.2.89.dist-info}/WHEEL +0 -0
- {angr-9.2.87.dist-info → angr-9.2.89.dist-info}/entry_points.txt +0 -0
|
@@ -1,378 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# pylint:disable=no-self-use
|
|
3
|
-
__package__ = __package__ or "tests.analyses.cfg" # pylint:disable=redefined-builtin
|
|
4
|
-
|
|
5
|
-
import os
|
|
6
|
-
import unittest
|
|
7
|
-
import logging
|
|
8
|
-
import tempfile
|
|
9
|
-
from typing import TYPE_CHECKING, List, Sequence, Tuple
|
|
10
|
-
|
|
11
|
-
import angr
|
|
12
|
-
from angr.analyses import CFGFast
|
|
13
|
-
from angr.knowledge_plugins.cfg import MemoryData, MemoryDataSort
|
|
14
|
-
|
|
15
|
-
if TYPE_CHECKING:
|
|
16
|
-
from angr.knowledge_plugins.cfg import CFGModel
|
|
17
|
-
from angr.knowledge_plugins.functions import Function, FunctionManager
|
|
18
|
-
|
|
19
|
-
from ...common import bin_location
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
log = logging.getLogger(__name__)
|
|
23
|
-
log.setLevel(logging.DEBUG)
|
|
24
|
-
FAUXWARE_PATH = os.path.join(bin_location, "tests", "x86_64", "fauxware")
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def apply_patches(proj: angr.Project, patches: List[Tuple[int, str]]):
|
|
28
|
-
for addr, asm in patches:
|
|
29
|
-
patch_bytes = proj.arch.keystone.asm(asm, addr, as_bytes=True)[0]
|
|
30
|
-
proj.kb.patches.add_patch(addr, patch_bytes)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def assert_models_equal(model_a: "CFGModel", model_b: "CFGModel"):
|
|
34
|
-
assert model_a.graph.nodes() == model_b.graph.nodes()
|
|
35
|
-
assert model_a.graph.edges() == model_b.graph.edges()
|
|
36
|
-
# FIXME: Check more
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def assert_function_graphs_equal(function_a: "Function", function_b: "Function"):
|
|
40
|
-
nodes_a = function_a.graph.nodes()
|
|
41
|
-
nodes_b = function_b.graph.nodes()
|
|
42
|
-
if nodes_a != nodes_b:
|
|
43
|
-
log.error("Differing nodes!\nFunction:%s\nNodes A: %s\nNodes B: %s", function_a, nodes_a, nodes_b)
|
|
44
|
-
assert False
|
|
45
|
-
# FIXME: Check more
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def assert_all_function_equal(functions_a: "FunctionManager", functions_b: "FunctionManager"):
|
|
49
|
-
for f in functions_b:
|
|
50
|
-
assert f in functions_a, f"Extra function: {functions_b[f]}"
|
|
51
|
-
for f in functions_a:
|
|
52
|
-
assert f in functions_b, f"Missing function: {functions_a[f]}"
|
|
53
|
-
assert_function_graphs_equal(functions_a[f], functions_b[f])
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
class TestCfgCombination(unittest.TestCase):
|
|
57
|
-
"""
|
|
58
|
-
Tests that CFGFast can run with a prior model.
|
|
59
|
-
"""
|
|
60
|
-
|
|
61
|
-
def test_cfgfast_combine_with_full_model(self):
|
|
62
|
-
"""Run CFGFast once, then again with the model of the first."""
|
|
63
|
-
proj = angr.Project(FAUXWARE_PATH, auto_load_libs=False)
|
|
64
|
-
cfg_a = proj.analyses[CFGFast].prep()()
|
|
65
|
-
cfg_b = proj.analyses[CFGFast].prep()(model=cfg_a.model.copy())
|
|
66
|
-
assert_models_equal(cfg_a.model, cfg_b.model)
|
|
67
|
-
assert_all_function_equal(cfg_a.functions, cfg_b.functions)
|
|
68
|
-
|
|
69
|
-
def test_cfgfast_combine_with_partial_model(self):
|
|
70
|
-
"""Run CFGFast on a region, then again on a second region with the model of the first."""
|
|
71
|
-
|
|
72
|
-
# Initial analysis just to pick up expected addresses
|
|
73
|
-
proj = angr.Project(FAUXWARE_PATH, auto_load_libs=False)
|
|
74
|
-
cfg = proj.analyses[CFGFast].prep()()
|
|
75
|
-
accepted_addr = cfg.functions["accepted"].addr
|
|
76
|
-
rejected_addr = cfg.functions["rejected"].addr
|
|
77
|
-
accepted_regions = [(n.addr, n.addr + n.size) for n in cfg.functions["accepted"].nodes]
|
|
78
|
-
rejected_regions = [(n.addr, n.addr + n.size) for n in cfg.functions["rejected"].nodes]
|
|
79
|
-
|
|
80
|
-
# Run partial analysis on the nodes we care about
|
|
81
|
-
proj = angr.Project(FAUXWARE_PATH, auto_load_libs=False)
|
|
82
|
-
cfg = proj.analyses[CFGFast].prep()(regions=accepted_regions)
|
|
83
|
-
assert accepted_addr in cfg.functions.function_addrs_set
|
|
84
|
-
assert rejected_addr not in cfg.functions.function_addrs_set
|
|
85
|
-
|
|
86
|
-
# Check continued analysis over another region combines correctly
|
|
87
|
-
cfg = proj.analyses[CFGFast].prep()(regions=rejected_regions, model=cfg.model.copy())
|
|
88
|
-
assert accepted_addr in cfg.functions.function_addrs_set
|
|
89
|
-
assert rejected_addr in cfg.functions.function_addrs_set
|
|
90
|
-
|
|
91
|
-
# Check analysis over union of regions yields same result
|
|
92
|
-
proj = angr.Project(FAUXWARE_PATH, auto_load_libs=False)
|
|
93
|
-
regions = accepted_regions + rejected_regions
|
|
94
|
-
cfg_combined = proj.analyses[CFGFast].prep()(regions=regions)
|
|
95
|
-
assert_models_equal(cfg.model, cfg_combined.model)
|
|
96
|
-
assert_all_function_equal(cfg.functions, cfg_combined.functions)
|
|
97
|
-
|
|
98
|
-
# FIXME: Add test of first analyzing a function A, then analyzing a function B called by A
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
class TestCfgReclassification(unittest.TestCase):
|
|
102
|
-
"""
|
|
103
|
-
Tests that code/data can be reclassified in CFG.
|
|
104
|
-
"""
|
|
105
|
-
|
|
106
|
-
def test_cfgfast_preclassify_code_as_data(self):
|
|
107
|
-
"""Classify a code region as data in an empty model, run CFGFast, ensure region remains classified as data."""
|
|
108
|
-
proj = angr.Project(FAUXWARE_PATH, auto_load_libs=False)
|
|
109
|
-
model = proj.kb.cfgs.new_model("initial")
|
|
110
|
-
md = MemoryData(0x40069D, 22, MemoryDataSort.String)
|
|
111
|
-
model.memory_data[md.addr] = md.copy()
|
|
112
|
-
cfg = proj.analyses[CFGFast].prep()(model=model)
|
|
113
|
-
assert cfg.model.memory_data[md.addr] == md
|
|
114
|
-
|
|
115
|
-
# Make sure the memory data item is not covered by any node
|
|
116
|
-
assert len(cfg.functions["authenticate"].graph.nodes) == 5
|
|
117
|
-
for n in cfg.functions["authenticate"].graph.nodes:
|
|
118
|
-
assert md.addr >= (n.addr + n.size) or n.addr >= (md.addr + md.size)
|
|
119
|
-
if (n.addr + n.size) == md.addr:
|
|
120
|
-
log.debug("Found adjacent node %s", n)
|
|
121
|
-
# FIXME: Successor address is still the same
|
|
122
|
-
|
|
123
|
-
# FIXME: Also test at function boundary
|
|
124
|
-
|
|
125
|
-
def test_cfgfast_reclassify_code_as_data(self):
|
|
126
|
-
"""Run CFGFast, re-classify code within a function as data, then re-flow the function."""
|
|
127
|
-
proj = angr.Project(FAUXWARE_PATH, auto_load_libs=False)
|
|
128
|
-
|
|
129
|
-
# Initial analysis
|
|
130
|
-
cfg = proj.analyses[CFGFast].prep()()
|
|
131
|
-
func = cfg.functions["authenticate"]
|
|
132
|
-
function_addr = func.addr
|
|
133
|
-
original_number_of_nodes = len(func.graph.nodes)
|
|
134
|
-
|
|
135
|
-
# Define the data region and run analysis for function reconstruction
|
|
136
|
-
md = MemoryData(0x40069D, 22, MemoryDataSort.String)
|
|
137
|
-
cfg.model.memory_data[md.addr] = md.copy()
|
|
138
|
-
cfg.model.clear_region_for_reflow(func.addr)
|
|
139
|
-
cfg = proj.analyses[CFGFast].prep()(
|
|
140
|
-
symbols=False,
|
|
141
|
-
function_prologues=False,
|
|
142
|
-
start_at_entry=False,
|
|
143
|
-
force_smart_scan=False,
|
|
144
|
-
force_complete_scan=False,
|
|
145
|
-
function_starts=[function_addr],
|
|
146
|
-
model=cfg.model,
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
# Check memory data remains as configured and is not overlapped by any node
|
|
150
|
-
assert cfg.model.memory_data[md.addr] == md
|
|
151
|
-
assert len(cfg.functions["authenticate"].graph.nodes) == 5
|
|
152
|
-
for n in cfg.functions["authenticate"].graph.nodes:
|
|
153
|
-
assert md.addr >= (n.addr + n.size) or n.addr >= (md.addr + md.size)
|
|
154
|
-
|
|
155
|
-
# Now re-define the data as code again and ensure we have the correct number of nodes
|
|
156
|
-
del cfg.model.memory_data[md.addr]
|
|
157
|
-
cfg.model.clear_region_for_reflow(func.addr)
|
|
158
|
-
cfg = proj.analyses[CFGFast].prep()(
|
|
159
|
-
symbols=False,
|
|
160
|
-
function_prologues=False,
|
|
161
|
-
start_at_entry=False,
|
|
162
|
-
force_smart_scan=False,
|
|
163
|
-
force_complete_scan=False,
|
|
164
|
-
function_starts=[function_addr],
|
|
165
|
-
model=cfg.model,
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
assert len(cfg.functions["authenticate"].graph.nodes) == original_number_of_nodes
|
|
169
|
-
|
|
170
|
-
# FIXME: Test at function boundary
|
|
171
|
-
|
|
172
|
-
# FIXME: Test at partial offset into some data item
|
|
173
|
-
def test_cfgfast_preclassify_data_as_code(self):
|
|
174
|
-
"""Classify some code that would not normally be classified as code."""
|
|
175
|
-
code = """
|
|
176
|
-
_start:
|
|
177
|
-
ret
|
|
178
|
-
|
|
179
|
-
not_discovered:
|
|
180
|
-
xor rax, rax
|
|
181
|
-
mov rcx, 5
|
|
182
|
-
.here:
|
|
183
|
-
inc rax
|
|
184
|
-
dec rcx
|
|
185
|
-
jnz .here
|
|
186
|
-
ret
|
|
187
|
-
"""
|
|
188
|
-
|
|
189
|
-
not_discovered_addr = 0x1
|
|
190
|
-
proj = angr.load_shellcode(code, "AMD64")
|
|
191
|
-
cfg = proj.analyses[CFGFast].prep()(force_smart_scan=False)
|
|
192
|
-
assert len(cfg.functions) == 1
|
|
193
|
-
|
|
194
|
-
proj = angr.load_shellcode(code, "AMD64")
|
|
195
|
-
cfg = proj.analyses[CFGFast].prep()(force_smart_scan=False, function_starts=[not_discovered_addr])
|
|
196
|
-
assert len(cfg.functions) == 2
|
|
197
|
-
assert len(cfg.functions[not_discovered_addr].block_addrs) == 3
|
|
198
|
-
|
|
199
|
-
def test_cfgfast_reclassify_data_as_code(self):
|
|
200
|
-
"""Run CFGFast, then re-classify some assumed data as code and run again."""
|
|
201
|
-
code = """
|
|
202
|
-
_start:
|
|
203
|
-
mov rax, [not_discovered]
|
|
204
|
-
ret
|
|
205
|
-
|
|
206
|
-
not_discovered:
|
|
207
|
-
xor rax, rax
|
|
208
|
-
mov rcx, 5
|
|
209
|
-
.here:
|
|
210
|
-
inc rax
|
|
211
|
-
dec rcx
|
|
212
|
-
jnz .here
|
|
213
|
-
ret
|
|
214
|
-
"""
|
|
215
|
-
|
|
216
|
-
proj = angr.load_shellcode(code, "AMD64")
|
|
217
|
-
cfg = proj.analyses[CFGFast].prep()(force_smart_scan=False)
|
|
218
|
-
assert len(cfg.functions) == 1
|
|
219
|
-
not_discovered_addr = 0xB
|
|
220
|
-
del cfg.model.memory_data[not_discovered_addr]
|
|
221
|
-
cfg = proj.analyses[CFGFast].prep()(
|
|
222
|
-
start_at_entry=False, force_smart_scan=False, function_starts=[not_discovered_addr], model=cfg.model
|
|
223
|
-
)
|
|
224
|
-
assert len(cfg.functions) == 2
|
|
225
|
-
assert len(cfg.functions[0xB].block_addrs) == 3
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
class TestCfgPatching(unittest.TestCase):
|
|
229
|
-
"""
|
|
230
|
-
Test that patches made to the binary are correctly reflected in CFG.
|
|
231
|
-
"""
|
|
232
|
-
|
|
233
|
-
def _test_patch(self, patches: Sequence[Tuple[int, str]]):
|
|
234
|
-
unpatched_binary_path = FAUXWARE_PATH
|
|
235
|
-
common_cfg_options = {
|
|
236
|
-
"normalize": True,
|
|
237
|
-
"resolve_indirect_jumps": True,
|
|
238
|
-
"data_references": True,
|
|
239
|
-
# "force_smart_scan": False,
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
# Create and load a pre-patched binary
|
|
243
|
-
log.debug("Recovering pre-patched CFG")
|
|
244
|
-
proj = angr.Project(unpatched_binary_path, auto_load_libs=False)
|
|
245
|
-
apply_patches(proj, patches)
|
|
246
|
-
|
|
247
|
-
with tempfile.NamedTemporaryFile(prefix="fauxware-patched-", delete=False) as f:
|
|
248
|
-
f.write(proj.kb.patches.apply_patches_to_binary())
|
|
249
|
-
f.close()
|
|
250
|
-
prepatched_proj = angr.Project(f.name, auto_load_libs=False)
|
|
251
|
-
expected_cfg = prepatched_proj.analyses[CFGFast].prep()(**common_cfg_options)
|
|
252
|
-
|
|
253
|
-
# Now create a new project, recover CFG, then patch and recover CFG again
|
|
254
|
-
proj = angr.Project(unpatched_binary_path, auto_load_libs=False)
|
|
255
|
-
log.debug("Recovering CFG before patching")
|
|
256
|
-
cfg_before_patching = proj.analyses[CFGFast].prep()(**common_cfg_options)
|
|
257
|
-
apply_patches(proj, patches)
|
|
258
|
-
|
|
259
|
-
log.debug("Recovering CFG after patching")
|
|
260
|
-
for p in proj.kb.patches.values():
|
|
261
|
-
cfg_before_patching.model.clear_region_for_reflow(p.addr, len(p.new_bytes))
|
|
262
|
-
cfg_after_patching = proj.analyses[CFGFast].prep()(**common_cfg_options, model=cfg_before_patching.model)
|
|
263
|
-
|
|
264
|
-
# Verify that the CFG of the patched binary matches the CFG of the pre-patched binary
|
|
265
|
-
assert_models_equal(expected_cfg.model, cfg_after_patching.model)
|
|
266
|
-
|
|
267
|
-
os.unlink(f.name)
|
|
268
|
-
|
|
269
|
-
#
|
|
270
|
-
# Patches that do not change block or function size
|
|
271
|
-
#
|
|
272
|
-
|
|
273
|
-
def test_cfg_patch_const_operand(self):
|
|
274
|
-
"""
|
|
275
|
-
Patch a block, changing a data reference, with no effect on control.
|
|
276
|
-
|
|
277
|
-
Change print of "Username: " to "Password: ".
|
|
278
|
-
"""
|
|
279
|
-
self._test_patch([(0x400734, "mov edi, 0x400920")])
|
|
280
|
-
|
|
281
|
-
def test_cfg_patch_ret_value(self):
|
|
282
|
-
"""
|
|
283
|
-
Patch a block to redirect control, without changing the graph.
|
|
284
|
-
|
|
285
|
-
Change return value of `authenticate` in rejection branch to 1.
|
|
286
|
-
"""
|
|
287
|
-
self._test_patch([(0x4006E6, "mov eax, 1")])
|
|
288
|
-
|
|
289
|
-
def test_cfg_patch_branch(self):
|
|
290
|
-
"""
|
|
291
|
-
Patch a block, changing the graph.
|
|
292
|
-
|
|
293
|
-
Patch `authenticate` to always jump to accept branch, eliminating 1 block.
|
|
294
|
-
"""
|
|
295
|
-
self._test_patch([(0x4006DD, "jne 0x4006df")])
|
|
296
|
-
|
|
297
|
-
def test_cfg_patch_call_target(self):
|
|
298
|
-
"""
|
|
299
|
-
Patch a block, changing the graph, eliminate a cross reference.
|
|
300
|
-
|
|
301
|
-
Change call of `rejected` to `accepted`.
|
|
302
|
-
"""
|
|
303
|
-
self._test_patch([(0x4007CE, "call 0x4006ed")])
|
|
304
|
-
|
|
305
|
-
# FIXME: Patches that change indirect jumps
|
|
306
|
-
|
|
307
|
-
#
|
|
308
|
-
# Patches that shrink blocks/function
|
|
309
|
-
#
|
|
310
|
-
|
|
311
|
-
def test_cfg_patch_shrink_encoding(self):
|
|
312
|
-
"""
|
|
313
|
-
Shorten a block, but do not change graph.
|
|
314
|
-
|
|
315
|
-
Use a shorter instruction encoding.
|
|
316
|
-
"""
|
|
317
|
-
self._test_patch([(0x4006DF, "xor eax, eax; inc eax; jmp 0x4006eb")])
|
|
318
|
-
|
|
319
|
-
def test_cfg_patch_shrink_branch(self):
|
|
320
|
-
"""
|
|
321
|
-
Shorten a block, changing the graph.
|
|
322
|
-
|
|
323
|
-
Remove `strcmp` check in `authenticate`, just jump to accept branch.
|
|
324
|
-
"""
|
|
325
|
-
self._test_patch([(0x4006DB, "jmp 0x4006df")])
|
|
326
|
-
|
|
327
|
-
def test_cfg_patch_shrink_ret_value(self):
|
|
328
|
-
"""
|
|
329
|
-
Shorten a block, truncating a function.
|
|
330
|
-
|
|
331
|
-
Patch `authenticate` to always return 1
|
|
332
|
-
"""
|
|
333
|
-
self._test_patch([(0x400664, "xor rax, rax; inc rax; ret")])
|
|
334
|
-
|
|
335
|
-
#
|
|
336
|
-
# Patches that grow blocks
|
|
337
|
-
#
|
|
338
|
-
|
|
339
|
-
def test_cfg_patch_grow_block_fallthru(self):
|
|
340
|
-
"""
|
|
341
|
-
Patch a block to cover another block.
|
|
342
|
-
|
|
343
|
-
Ignore return value of `authenticate`, fallthru to accept branch.
|
|
344
|
-
"""
|
|
345
|
-
self._test_patch([(0x4007BB, "nop; nop;")])
|
|
346
|
-
|
|
347
|
-
def test_cfg_patch_grow_nocall(self):
|
|
348
|
-
"""
|
|
349
|
-
Patch a block to eliminate all cross references to a function.
|
|
350
|
-
|
|
351
|
-
Patch out call to `authenticate`, fall thru.
|
|
352
|
-
"""
|
|
353
|
-
self._test_patch([(0x4007AE, "xor rax, rax; nop; nop")])
|
|
354
|
-
|
|
355
|
-
def test_cfg_patch_grow_into_inter_function_padding(self):
|
|
356
|
-
"""
|
|
357
|
-
Patch a block to grow into padded space between functions.
|
|
358
|
-
|
|
359
|
-
Prepend several NOPs to the last block of `main`.
|
|
360
|
-
"""
|
|
361
|
-
self._test_patch([(0x4007D3, "nop; nop; nop; nop; leave; ret")])
|
|
362
|
-
|
|
363
|
-
def test_cfg_patch_grow_function_fallthru(self):
|
|
364
|
-
"""
|
|
365
|
-
Patch a block that extends into another function.
|
|
366
|
-
|
|
367
|
-
Cut off the end of `authenticate` so it falls into `accepted`.
|
|
368
|
-
"""
|
|
369
|
-
self._test_patch([(0x4006EC, "nop")])
|
|
370
|
-
# Will we have two functions? accepted() is still called so it will probably mark a function
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
if __name__ == "__main__":
|
|
374
|
-
logging.basicConfig()
|
|
375
|
-
log.setLevel(logging.DEBUG)
|
|
376
|
-
logging.getLogger("angr.analyses.cfg.cfg_fast").setLevel(logging.DEBUG)
|
|
377
|
-
logging.getLogger("angr.analyses.cfg.cfg_base").setLevel(logging.DEBUG)
|
|
378
|
-
unittest.main()
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
__package__ = __package__ or "tests.analyses.cfg" # pylint:disable=redefined-builtin
|
|
3
|
-
|
|
4
|
-
import os
|
|
5
|
-
import unittest
|
|
6
|
-
|
|
7
|
-
import angr
|
|
8
|
-
|
|
9
|
-
from ...common import bin_location, slow_test
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
test_location = os.path.join(bin_location, "tests")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# pylint: disable=missing-class-docstring
|
|
16
|
-
# pylint: disable=no-self-use
|
|
17
|
-
class TestCfgRustGotResolution(unittest.TestCase):
|
|
18
|
-
@slow_test
|
|
19
|
-
def test_rust_got_resolution(self):
|
|
20
|
-
# Test a simple Rust binary sample.
|
|
21
|
-
#
|
|
22
|
-
# Rust compiler may insert some non-external functions into GOT.
|
|
23
|
-
# This tests whether angr can resolve indirect function calls to GOT entries in Rust binaries.
|
|
24
|
-
|
|
25
|
-
path = os.path.join(test_location, "x86_64", "rust_hello_world")
|
|
26
|
-
p = angr.Project(path, auto_load_libs=False)
|
|
27
|
-
|
|
28
|
-
cfg = p.analyses.CFGFast(resolve_indirect_jumps=True)
|
|
29
|
-
|
|
30
|
-
# angr should be able to resolve the indirect call in main function
|
|
31
|
-
main = cfg.kb.functions[p.loader.find_symbol("_ZN16rust_hello_world4main17h932c4676a11c63c3E").rebased_addr]
|
|
32
|
-
assert not main.has_unresolved_calls
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if __name__ == "__main__":
|
|
36
|
-
unittest.main()
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
__package__ = __package__ or "tests.analyses.cfg" # pylint:disable=redefined-builtin
|
|
3
|
-
|
|
4
|
-
import os
|
|
5
|
-
import unittest
|
|
6
|
-
|
|
7
|
-
import angr
|
|
8
|
-
|
|
9
|
-
from ...common import bin_location
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
test_location = os.path.join(bin_location, "tests")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# pylint: disable=missing-class-docstring
|
|
16
|
-
# pylint: disable=no-self-use
|
|
17
|
-
class TestCfgThumbFirmware(unittest.TestCase):
|
|
18
|
-
def test_thumb_firmware_cfg(self):
|
|
19
|
-
# Test an ARM firmware sample.
|
|
20
|
-
#
|
|
21
|
-
# This tests CFG, but also the Gym (the ThumbSpotter, etc)
|
|
22
|
-
# Also requires proper relocs support, or You're Gonna Have a Bad Time(tm)
|
|
23
|
-
# In short, a very comprehensive high level test
|
|
24
|
-
|
|
25
|
-
path = os.path.join(test_location, "armel", "i2c_master_read-nucleol152re.elf")
|
|
26
|
-
p = angr.Project(path, auto_load_libs=False)
|
|
27
|
-
|
|
28
|
-
# This is the canonical way to carve up a nasty firmware thing.
|
|
29
|
-
|
|
30
|
-
cfg = p.analyses.CFGFast(
|
|
31
|
-
resolve_indirect_jumps=True, force_smart_scan=False, force_complete_scan=False, normalize=True
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
# vfprintf should return; this function has a weird C++ thing that gets compiled as a tail-call.
|
|
35
|
-
# The function itself must return, and _NOT_ contain its callee.
|
|
36
|
-
vfprintf = cfg.kb.functions[p.loader.find_symbol("vfprintf").rebased_addr]
|
|
37
|
-
assert vfprintf.returning
|
|
38
|
-
assert len(list(vfprintf.blocks)) == 1
|
|
39
|
-
# The function should have one "transition"
|
|
40
|
-
block = list(vfprintf.endpoints_with_type["transition"])[0]
|
|
41
|
-
assert len(block.successors()) == 1
|
|
42
|
-
succ = list(block.successors())[0]
|
|
43
|
-
assert succ.addr == 0x080081DD
|
|
44
|
-
f2 = p.kb.functions[succ.addr]
|
|
45
|
-
assert f2.name == "_vfprintf_r"
|
|
46
|
-
assert f2.returning
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if __name__ == "__main__":
|
|
50
|
-
unittest.main()
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
__package__ = __package__ or "tests.analyses.cfg" # pylint:disable=redefined-builtin
|
|
3
|
-
|
|
4
|
-
import os
|
|
5
|
-
import unittest
|
|
6
|
-
|
|
7
|
-
import angr
|
|
8
|
-
|
|
9
|
-
from ...common import bin_location
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
test_location = os.path.join(bin_location, "tests")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# pylint: disable=missing-class-docstring
|
|
16
|
-
# pylint: disable=no-self-use
|
|
17
|
-
class TestCfgVexPostprocessor(unittest.TestCase):
|
|
18
|
-
def test_issue_1172(self):
|
|
19
|
-
path = os.path.join(test_location, "x86_64", "cfg_issue_1172")
|
|
20
|
-
p = angr.Project(path, auto_load_libs=False)
|
|
21
|
-
|
|
22
|
-
# it should not crash
|
|
23
|
-
_ = p.analyses.CFG()
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if __name__ == "__main__":
|
|
27
|
-
unittest.main()
|