angr 9.2.134__py3-none-manylinux2014_x86_64.whl → 9.2.136__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 +1 -1
- angr/analyses/__init__.py +5 -8
- angr/analyses/analysis.py +4 -0
- angr/analyses/backward_slice.py +1 -2
- angr/analyses/binary_optimizer.py +3 -4
- angr/analyses/bindiff.py +4 -6
- angr/analyses/boyscout.py +1 -3
- angr/analyses/callee_cleanup_finder.py +4 -4
- angr/analyses/calling_convention/__init__.py +6 -0
- angr/analyses/{calling_convention.py → calling_convention/calling_convention.py} +32 -64
- angr/analyses/calling_convention/fact_collector.py +502 -0
- angr/analyses/calling_convention/utils.py +57 -0
- angr/analyses/cdg.py +1 -2
- angr/analyses/cfg/cfb.py +1 -3
- angr/analyses/cfg/cfg.py +2 -2
- angr/analyses/cfg/cfg_base.py +37 -35
- angr/analyses/cfg/cfg_emulated.py +1 -1
- angr/analyses/cfg/cfg_fast.py +62 -15
- angr/analyses/cfg/cfg_fast_soot.py +1 -1
- angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
- angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +46 -10
- angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +5 -1
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +50 -14
- angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
- angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +24 -5
- angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +2 -5
- angr/analyses/complete_calling_conventions.py +32 -3
- angr/analyses/congruency_check.py +2 -3
- angr/analyses/data_dep/data_dependency_analysis.py +2 -2
- angr/analyses/ddg.py +1 -4
- angr/analyses/decompiler/ail_simplifier.py +3 -4
- angr/analyses/decompiler/clinic.py +42 -7
- angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
- angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +2 -2
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +1 -1
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +0 -6
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +2 -7
- angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +0 -6
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +0 -6
- angr/analyses/decompiler/structuring/phoenix.py +1 -1
- angr/analyses/disassembly.py +5 -5
- angr/analyses/fcp/__init__.py +4 -0
- angr/analyses/fcp/fcp.py +429 -0
- angr/analyses/identifier/identify.py +1 -3
- angr/analyses/loopfinder.py +4 -3
- angr/analyses/patchfinder.py +1 -1
- angr/analyses/propagator/engine_base.py +4 -3
- angr/analyses/propagator/propagator.py +14 -53
- angr/analyses/reassembler.py +1 -2
- angr/analyses/s_propagator.py +1 -3
- angr/analyses/soot_class_hierarchy.py +1 -2
- angr/analyses/stack_pointer_tracker.py +18 -2
- angr/analyses/static_hooker.py +1 -2
- angr/analyses/typehoon/simple_solver.py +2 -2
- angr/analyses/variable_recovery/engine_vex.py +5 -0
- angr/analyses/variable_recovery/variable_recovery_fast.py +1 -2
- angr/analyses/veritesting.py +4 -7
- angr/analyses/vfg.py +1 -1
- angr/analyses/vsa_ddg.py +1 -2
- angr/block.py +3 -2
- angr/callable.py +1 -3
- angr/calling_conventions.py +15 -7
- angr/codenode.py +5 -1
- angr/concretization_strategies/__init__.py +1 -83
- angr/concretization_strategies/any.py +2 -1
- angr/concretization_strategies/any_named.py +1 -1
- angr/concretization_strategies/base.py +81 -0
- angr/concretization_strategies/controlled_data.py +2 -1
- angr/concretization_strategies/eval.py +2 -1
- angr/concretization_strategies/logging.py +3 -1
- angr/concretization_strategies/max.py +2 -1
- angr/concretization_strategies/nonzero.py +2 -1
- angr/concretization_strategies/nonzero_range.py +2 -1
- angr/concretization_strategies/norepeats.py +2 -1
- angr/concretization_strategies/norepeats_range.py +2 -1
- angr/concretization_strategies/range.py +2 -1
- angr/concretization_strategies/signed_add.py +2 -1
- angr/concretization_strategies/single.py +2 -1
- angr/concretization_strategies/solutions.py +2 -1
- angr/concretization_strategies/unlimited_range.py +2 -1
- angr/engines/__init__.py +8 -5
- angr/engines/engine.py +3 -5
- angr/engines/failure.py +4 -5
- angr/engines/procedure.py +5 -7
- angr/engines/soot/expressions/__init__.py +22 -23
- angr/engines/soot/expressions/base.py +4 -4
- angr/engines/soot/expressions/invoke.py +1 -2
- angr/engines/soot/statements/__init__.py +9 -10
- angr/engines/soot/values/__init__.py +9 -10
- angr/engines/soot/values/arrayref.py +3 -3
- angr/engines/soot/values/instancefieldref.py +3 -2
- angr/engines/successors.py +7 -6
- angr/engines/syscall.py +4 -6
- angr/engines/unicorn.py +3 -2
- angr/engines/vex/claripy/ccall.py +8 -10
- angr/engines/vex/claripy/datalayer.py +4 -5
- angr/exploration_techniques/__init__.py +0 -2
- angr/exploration_techniques/spiller.py +1 -3
- angr/exploration_techniques/stochastic.py +2 -3
- angr/factory.py +3 -9
- angr/knowledge_plugins/cfg/cfg_model.py +20 -17
- angr/knowledge_plugins/functions/function.py +74 -77
- angr/knowledge_plugins/functions/function_manager.py +14 -7
- angr/knowledge_plugins/functions/function_parser.py +1 -1
- angr/knowledge_plugins/functions/soot_function.py +16 -16
- angr/knowledge_plugins/propagations/propagation_model.py +4 -5
- angr/knowledge_plugins/propagations/states.py +0 -511
- angr/procedures/libc/memcpy.py +4 -4
- angr/procedures/procedure_dict.py +3 -2
- angr/protos/__init__.py +2 -5
- angr/protos/cfg_pb2.py +21 -18
- angr/protos/function_pb2.py +17 -14
- angr/protos/primitives_pb2.py +44 -39
- angr/protos/variables_pb2.py +36 -31
- angr/protos/xrefs_pb2.py +15 -12
- angr/sim_procedure.py +15 -16
- angr/sim_variable.py +13 -1
- angr/simos/__init__.py +2 -0
- angr/simos/javavm.py +4 -6
- angr/simos/xbox.py +32 -0
- angr/state_plugins/__init__.py +0 -2
- angr/state_plugins/callstack.py +4 -4
- angr/state_plugins/cgc.py +3 -2
- angr/state_plugins/gdb.py +6 -5
- angr/state_plugins/globals.py +1 -2
- angr/state_plugins/heap/heap_brk.py +1 -2
- angr/state_plugins/history.py +10 -12
- angr/state_plugins/inspect.py +3 -5
- angr/state_plugins/libc.py +2 -2
- angr/state_plugins/log.py +8 -10
- angr/state_plugins/loop_data.py +1 -2
- angr/state_plugins/posix.py +7 -7
- angr/state_plugins/preconstrainer.py +2 -3
- angr/state_plugins/scratch.py +5 -8
- angr/state_plugins/sim_action.py +3 -3
- angr/state_plugins/solver.py +8 -3
- angr/state_plugins/symbolizer.py +5 -4
- angr/state_plugins/uc_manager.py +3 -3
- angr/state_plugins/unicorn_engine.py +5 -1
- angr/state_plugins/view.py +3 -5
- angr/storage/file.py +3 -5
- angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
- angr/storage/memory_mixins/bvv_conversion_mixin.py +3 -3
- angr/storage/memory_mixins/clouseau_mixin.py +1 -3
- angr/storage/memory_mixins/name_resolution_mixin.py +1 -3
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +13 -15
- angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -22
- angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
- angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
- angr/storage/memory_mixins/paged_memory/privileged_mixin.py +3 -4
- angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
- angr/storage/memory_mixins/smart_find_mixin.py +1 -1
- angr/storage/memory_mixins/underconstrained_mixin.py +1 -1
- angr/storage/memory_mixins/unwrapper_mixin.py +1 -3
- angr/utils/bits.py +13 -0
- angr/utils/enums_conv.py +28 -12
- angr/utils/segment_list.py +25 -22
- angr/utils/timing.py +18 -1
- angr/vaults.py +5 -6
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/METADATA +6 -6
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/RECORD +168 -164
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/WHEEL +1 -1
- angr/analyses/propagator/outdated_definition_walker.py +0 -159
- angr/analyses/propagator/tmpvar_finder.py +0 -18
- angr/engines/concrete.py +0 -180
- angr/exploration_techniques/symbion.py +0 -80
- angr/state_plugins/concrete.py +0 -295
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/LICENSE +0 -0
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/entry_points.txt +0 -0
- {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/top_level.txt +0 -0
angr/analyses/cfg/cfg_base.py
CHANGED
|
@@ -1570,13 +1570,13 @@ class CFGBase(Analysis):
|
|
|
1570
1570
|
# TODO: Is it required that PLT stubs are always aligned by 16? If so, on what architectures and platforms is it
|
|
1571
1571
|
# TODO: enforced?
|
|
1572
1572
|
|
|
1573
|
-
tmp_functions = self.kb.functions
|
|
1573
|
+
tmp_functions = self.kb.functions
|
|
1574
1574
|
|
|
1575
1575
|
for function in tmp_functions.values():
|
|
1576
1576
|
function.mark_nonreturning_calls_endpoints()
|
|
1577
1577
|
if function.returning is False:
|
|
1578
1578
|
# remove all FakeRet edges that are related to this function
|
|
1579
|
-
func_node = self.model.get_any_node(function.addr)
|
|
1579
|
+
func_node = self.model.get_any_node(function.addr, force_fastpath=True)
|
|
1580
1580
|
if func_node is not None:
|
|
1581
1581
|
callsite_nodes = [
|
|
1582
1582
|
src
|
|
@@ -1588,8 +1588,8 @@ class CFGBase(Analysis):
|
|
|
1588
1588
|
if data.get("jumpkind", None) == "Ijk_FakeRet":
|
|
1589
1589
|
self.graph.remove_edge(callsite_node, dst)
|
|
1590
1590
|
|
|
1591
|
-
# Clear old functions dict
|
|
1592
|
-
self.kb.functions.
|
|
1591
|
+
# Clear old functions dict by creating a new function manager
|
|
1592
|
+
self.kb.functions = FunctionManager(self.kb)
|
|
1593
1593
|
|
|
1594
1594
|
blockaddr_to_function = {}
|
|
1595
1595
|
traversed_cfg_nodes = set()
|
|
@@ -1602,7 +1602,7 @@ class CFGBase(Analysis):
|
|
|
1602
1602
|
if jumpkind == "Ijk_Call" or jumpkind.startswith("Ijk_Sys"):
|
|
1603
1603
|
function_nodes.add(dst)
|
|
1604
1604
|
|
|
1605
|
-
entry_node = self.model.get_any_node(self._binary.entry)
|
|
1605
|
+
entry_node = self.model.get_any_node(self._binary.entry, force_fastpath=True)
|
|
1606
1606
|
if entry_node is not None:
|
|
1607
1607
|
function_nodes.add(entry_node)
|
|
1608
1608
|
|
|
@@ -1663,7 +1663,7 @@ class CFGBase(Analysis):
|
|
|
1663
1663
|
secondary_function_nodes = set()
|
|
1664
1664
|
# add all function chunks ("functions" that are not called from anywhere)
|
|
1665
1665
|
for func_addr in tmp_functions:
|
|
1666
|
-
node = self.model.get_any_node(func_addr)
|
|
1666
|
+
node = self.model.get_any_node(func_addr, force_fastpath=True)
|
|
1667
1667
|
if node is None:
|
|
1668
1668
|
continue
|
|
1669
1669
|
if node.addr not in blockaddr_to_function:
|
|
@@ -1992,8 +1992,8 @@ class CFGBase(Analysis):
|
|
|
1992
1992
|
if not transition_found:
|
|
1993
1993
|
continue
|
|
1994
1994
|
|
|
1995
|
-
cfgnode_0 = self.model.get_any_node(block_node.addr)
|
|
1996
|
-
cfgnode_1 = self.model.get_any_node(addr_1)
|
|
1995
|
+
cfgnode_0 = self.model.get_any_node(block_node.addr, force_fastpath=True)
|
|
1996
|
+
cfgnode_1 = self.model.get_any_node(addr_1, force_fastpath=True)
|
|
1997
1997
|
|
|
1998
1998
|
if cfgnode_0 is None or cfgnode_1 is None:
|
|
1999
1999
|
continue
|
|
@@ -2089,7 +2089,7 @@ class CFGBase(Analysis):
|
|
|
2089
2089
|
continue
|
|
2090
2090
|
if func_addr in jumptable_entries:
|
|
2091
2091
|
# is there any call edge pointing to it?
|
|
2092
|
-
func_node = self.get_any_node(func_addr)
|
|
2092
|
+
func_node = self.get_any_node(func_addr, force_fastpath=True)
|
|
2093
2093
|
if func_node is not None:
|
|
2094
2094
|
in_edges = self.graph.in_edges(func_node, data=True)
|
|
2095
2095
|
has_transition_pred = None
|
|
@@ -2128,7 +2128,7 @@ class CFGBase(Analysis):
|
|
|
2128
2128
|
else:
|
|
2129
2129
|
is_syscall = self.project.simos.is_syscall_addr(addr)
|
|
2130
2130
|
|
|
2131
|
-
n = self.model.get_any_node(addr, is_syscall=is_syscall)
|
|
2131
|
+
n = self.model.get_any_node(addr, is_syscall=is_syscall, force_fastpath=True)
|
|
2132
2132
|
node = addr if n is None else self._to_snippet(n)
|
|
2133
2133
|
|
|
2134
2134
|
if isinstance(addr, SootAddressDescriptor):
|
|
@@ -2304,7 +2304,7 @@ class CFGBase(Analysis):
|
|
|
2304
2304
|
src_function = self._addr_to_function(src_addr, blockaddr_to_function, known_functions)
|
|
2305
2305
|
|
|
2306
2306
|
if src_addr not in src_function.block_addrs_set:
|
|
2307
|
-
n = self.model.get_any_node(src_addr)
|
|
2307
|
+
n = self.model.get_any_node(src_addr, force_fastpath=True)
|
|
2308
2308
|
node = src_addr if n is None else self._to_snippet(n)
|
|
2309
2309
|
self.kb.functions._add_node(src_function.addr, node)
|
|
2310
2310
|
|
|
@@ -2315,7 +2315,7 @@ class CFGBase(Analysis):
|
|
|
2315
2315
|
jumpkind = data["jumpkind"]
|
|
2316
2316
|
|
|
2317
2317
|
if jumpkind == "Ijk_Ret":
|
|
2318
|
-
n = self.model.get_any_node(src_addr)
|
|
2318
|
+
n = self.model.get_any_node(src_addr, force_fastpath=True)
|
|
2319
2319
|
from_node = src_addr if n is None else self._to_snippet(n)
|
|
2320
2320
|
self.kb.functions._add_return_from(src_function.addr, from_node, None)
|
|
2321
2321
|
|
|
@@ -2334,7 +2334,7 @@ class CFGBase(Analysis):
|
|
|
2334
2334
|
# It must be calling a function
|
|
2335
2335
|
dst_function = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
|
|
2336
2336
|
|
|
2337
|
-
n = self.model.get_any_node(src_addr)
|
|
2337
|
+
n = self.model.get_any_node(src_addr, force_fastpath=True)
|
|
2338
2338
|
if n is None:
|
|
2339
2339
|
src_snippet = self._to_snippet(addr=src_addr, base_state=self._base_state)
|
|
2340
2340
|
else:
|
|
@@ -2349,21 +2349,12 @@ class CFGBase(Analysis):
|
|
|
2349
2349
|
else:
|
|
2350
2350
|
fakeret_node = self._one_fakeret_node(all_edges)
|
|
2351
2351
|
|
|
2352
|
-
fakeret_snippet = None if fakeret_node is None else self._to_snippet(cfg_node=fakeret_node)
|
|
2353
|
-
|
|
2354
2352
|
if isinstance(dst_addr, SootAddressDescriptor):
|
|
2355
2353
|
dst_addr = dst_addr.method
|
|
2356
2354
|
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
dst_addr,
|
|
2361
|
-
fakeret_snippet,
|
|
2362
|
-
syscall=is_syscall,
|
|
2363
|
-
ins_addr=ins_addr,
|
|
2364
|
-
stmt_idx=stmt_idx,
|
|
2365
|
-
)
|
|
2366
|
-
|
|
2355
|
+
# determining the returning target
|
|
2356
|
+
return_to_outside = False
|
|
2357
|
+
returning_snippet = None
|
|
2367
2358
|
if dst_function.returning and fakeret_node is not None:
|
|
2368
2359
|
returning_target = src.addr + src.size
|
|
2369
2360
|
if returning_target not in blockaddr_to_function:
|
|
@@ -2372,9 +2363,9 @@ class CFGBase(Analysis):
|
|
|
2372
2363
|
else:
|
|
2373
2364
|
self._addr_to_function(returning_target, blockaddr_to_function, known_functions)
|
|
2374
2365
|
|
|
2375
|
-
|
|
2366
|
+
return_to_outside = blockaddr_to_function[returning_target] is not src_function
|
|
2376
2367
|
|
|
2377
|
-
n = self.model.get_any_node(returning_target)
|
|
2368
|
+
n = self.model.get_any_node(returning_target, force_fastpath=True)
|
|
2378
2369
|
if n is None:
|
|
2379
2370
|
try:
|
|
2380
2371
|
returning_snippet = self._to_snippet(addr=returning_target, base_state=self._base_state)
|
|
@@ -2384,17 +2375,28 @@ class CFGBase(Analysis):
|
|
|
2384
2375
|
else:
|
|
2385
2376
|
returning_snippet = self._to_snippet(cfg_node=n)
|
|
2386
2377
|
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2378
|
+
self.kb.functions._add_call_to(
|
|
2379
|
+
src_function.addr,
|
|
2380
|
+
src_snippet,
|
|
2381
|
+
dst_addr,
|
|
2382
|
+
retn_node=returning_snippet,
|
|
2383
|
+
syscall=is_syscall,
|
|
2384
|
+
ins_addr=ins_addr,
|
|
2385
|
+
stmt_idx=stmt_idx,
|
|
2386
|
+
return_to_outside=return_to_outside,
|
|
2387
|
+
)
|
|
2388
|
+
|
|
2389
|
+
if returning_snippet is not None:
|
|
2390
|
+
self.kb.functions._add_fakeret_to(
|
|
2391
|
+
src_function.addr, src_snippet, returning_snippet, confirmed=True, to_outside=return_to_outside
|
|
2392
|
+
)
|
|
2391
2393
|
|
|
2392
2394
|
elif jumpkind in ("Ijk_Boring", "Ijk_InvalICache", "Ijk_Exception"):
|
|
2393
2395
|
# convert src_addr and dst_addr to CodeNodes
|
|
2394
|
-
n = self.model.get_any_node(src_addr)
|
|
2396
|
+
n = self.model.get_any_node(src_addr, force_fastpath=True)
|
|
2395
2397
|
src_node = src_addr if n is None else self._to_snippet(cfg_node=n)
|
|
2396
2398
|
|
|
2397
|
-
n = self.model.get_any_node(dst_addr)
|
|
2399
|
+
n = self.model.get_any_node(dst_addr, force_fastpath=True)
|
|
2398
2400
|
dst_node = dst_addr if n is None else self._to_snippet(cfg_node=n)
|
|
2399
2401
|
|
|
2400
2402
|
if self._skip_unmapped_addrs:
|
|
@@ -2460,10 +2462,10 @@ class CFGBase(Analysis):
|
|
|
2460
2462
|
|
|
2461
2463
|
elif jumpkind == "Ijk_FakeRet":
|
|
2462
2464
|
# convert src_addr and dst_addr to CodeNodes
|
|
2463
|
-
n = self.model.get_any_node(src_addr)
|
|
2465
|
+
n = self.model.get_any_node(src_addr, force_fastpath=True)
|
|
2464
2466
|
src_node = src_addr if n is None else self._to_snippet(n)
|
|
2465
2467
|
|
|
2466
|
-
n = self.model.get_any_node(dst_addr)
|
|
2468
|
+
n = self.model.get_any_node(dst_addr, force_fastpath=True)
|
|
2467
2469
|
dst_node = dst_addr if n is None else self._to_snippet(n)
|
|
2468
2470
|
|
|
2469
2471
|
if dst_addr not in blockaddr_to_function:
|
|
@@ -2083,7 +2083,7 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
2083
2083
|
if src_node_key is None:
|
|
2084
2084
|
if dst_node is None:
|
|
2085
2085
|
raise ValueError("Either src_node_key or dst_node_key must be specified.")
|
|
2086
|
-
self.kb.functions.function(dst_node.function_address, create=True).
|
|
2086
|
+
self.kb.functions.function(dst_node.function_address, create=True)._register_node(True, dst_codenode)
|
|
2087
2087
|
return
|
|
2088
2088
|
|
|
2089
2089
|
src_node = self._graph_get_node(src_node_key, terminator_for_nonexistent_node=True)
|
angr/analyses/cfg/cfg_fast.py
CHANGED
|
@@ -135,9 +135,9 @@ class PendingJobs:
|
|
|
135
135
|
A collection of pending jobs during CFG recovery.
|
|
136
136
|
"""
|
|
137
137
|
|
|
138
|
-
def __init__(self,
|
|
138
|
+
def __init__(self, kb, deregister_job_callback):
|
|
139
139
|
self._jobs = OrderedDict() # A mapping between function addresses and lists of pending jobs
|
|
140
|
-
self.
|
|
140
|
+
self._kb = kb
|
|
141
141
|
self._deregister_job_callback = deregister_job_callback
|
|
142
142
|
|
|
143
143
|
self._returning_functions = set()
|
|
@@ -145,6 +145,10 @@ class PendingJobs:
|
|
|
145
145
|
# consecutive calls to cleanup().
|
|
146
146
|
self._job_count = 0
|
|
147
147
|
|
|
148
|
+
@property
|
|
149
|
+
def _functions(self):
|
|
150
|
+
return self._kb.functions
|
|
151
|
+
|
|
148
152
|
def __len__(self):
|
|
149
153
|
return self._job_count
|
|
150
154
|
|
|
@@ -1316,7 +1320,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1316
1320
|
self._known_thunks = self._find_thunks()
|
|
1317
1321
|
|
|
1318
1322
|
# Initialize variables used during analysis
|
|
1319
|
-
self._pending_jobs: PendingJobs = PendingJobs(self.
|
|
1323
|
+
self._pending_jobs: PendingJobs = PendingJobs(self.kb, self._deregister_analysis_job)
|
|
1320
1324
|
self._traced_addresses: set[int] = {a for a, n in self._nodes_by_addr.items() if n}
|
|
1321
1325
|
self._function_returns = defaultdict(set)
|
|
1322
1326
|
|
|
@@ -1498,6 +1502,18 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1498
1502
|
pass
|
|
1499
1503
|
|
|
1500
1504
|
def _function_completed(self, func_addr: int):
|
|
1505
|
+
if self.project.arch.name == "AMD64":
|
|
1506
|
+
# determine if the function is __rust_probestack
|
|
1507
|
+
func = self.kb.functions.get_by_addr(func_addr) if self.kb.functions.contains_addr(func_addr) else None
|
|
1508
|
+
if func is not None and len(func.block_addrs_set) == 3:
|
|
1509
|
+
block_bytes = {func.get_block(block_addr).bytes for block_addr in func.block_addrs_set}
|
|
1510
|
+
if block_bytes == {
|
|
1511
|
+
b"UH\x89\xe5I\x89\xc3I\x81\xfb\x00\x10\x00\x00v\x1c",
|
|
1512
|
+
b"H\x81\xec\x00\x10\x00\x00H\x85d$\x08I\x81\xeb\x00\x10\x00\x00I\x81\xfb\x00\x10\x00\x00w\xe4",
|
|
1513
|
+
b"L)\xdcH\x85d$\x08H\x01\xc4\xc9\xc3",
|
|
1514
|
+
}:
|
|
1515
|
+
func.info["is_rust_probestack"] = True
|
|
1516
|
+
|
|
1501
1517
|
if self._collect_data_ref and self.project is not None and ":" in self.project.arch.name:
|
|
1502
1518
|
# this is a pcode arch - use Clinic to recover data references
|
|
1503
1519
|
|
|
@@ -1744,6 +1760,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1744
1760
|
# Clean up
|
|
1745
1761
|
self._traced_addresses = None
|
|
1746
1762
|
self._lifter_deregister_readonly_regions()
|
|
1763
|
+
self._function_returns = None
|
|
1747
1764
|
|
|
1748
1765
|
self._finish_progress()
|
|
1749
1766
|
|
|
@@ -1825,19 +1842,18 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1825
1842
|
break
|
|
1826
1843
|
|
|
1827
1844
|
# special handling: some binaries do not have SecurityCookie set, but still contain _security_init_cookie
|
|
1828
|
-
if security_init_cookie_found is False:
|
|
1845
|
+
if security_init_cookie_found is False and self.functions.contains_addr(self.project.entry):
|
|
1829
1846
|
start_func = self.functions.get_by_addr(self.project.entry)
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
break
|
|
1847
|
+
for callee in start_func.transition_graph:
|
|
1848
|
+
if (
|
|
1849
|
+
isinstance(callee, Function)
|
|
1850
|
+
and not security_init_cookie_found
|
|
1851
|
+
and is_function_likely_security_init_cookie(callee)
|
|
1852
|
+
):
|
|
1853
|
+
security_init_cookie_found = True
|
|
1854
|
+
callee.is_default_name = False
|
|
1855
|
+
callee.name = "_security_init_cookie"
|
|
1856
|
+
break
|
|
1841
1857
|
|
|
1842
1858
|
def _post_process_string_references(self) -> None:
|
|
1843
1859
|
"""
|
|
@@ -4765,6 +4781,37 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
4765
4781
|
func = self.kb.functions.get_by_addr(func_addr)
|
|
4766
4782
|
func.info["get_pc"] = "ebx"
|
|
4767
4783
|
|
|
4784
|
+
# determine if the function uses ebp as a general purpose register or not
|
|
4785
|
+
if addr == func_addr or 0 < addr - func_addr <= 0x20:
|
|
4786
|
+
ebp_as_gpr = True
|
|
4787
|
+
cap = self._lift(addr, size=cfg_node.size).capstone
|
|
4788
|
+
for insn in cap.insns:
|
|
4789
|
+
if (
|
|
4790
|
+
insn.mnemonic == "mov"
|
|
4791
|
+
and len(insn.operands) == 2
|
|
4792
|
+
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4793
|
+
and insn.operands[1].type == capstone.x86.X86_OP_REG
|
|
4794
|
+
):
|
|
4795
|
+
if (
|
|
4796
|
+
insn.operands[0].reg == capstone.x86.X86_REG_EBP
|
|
4797
|
+
and insn.operands[1].reg == capstone.x86.X86_REG_ESP
|
|
4798
|
+
):
|
|
4799
|
+
ebp_as_gpr = False
|
|
4800
|
+
break
|
|
4801
|
+
elif (
|
|
4802
|
+
insn.mnemonic == "lea"
|
|
4803
|
+
and len(insn.operands) == 2
|
|
4804
|
+
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4805
|
+
and insn.operands[1].type == capstone.x86.X86_OP_MEM
|
|
4806
|
+
) and (
|
|
4807
|
+
insn.operands[0].reg == capstone.x86.X86_REG_EBP
|
|
4808
|
+
and insn.operands[1].mem.base == capstone.x86.X86_REG_ESP
|
|
4809
|
+
):
|
|
4810
|
+
ebp_as_gpr = False
|
|
4811
|
+
break
|
|
4812
|
+
func = self.kb.functions.get_by_addr(func_addr)
|
|
4813
|
+
func.info["bp_as_gpr"] = ebp_as_gpr
|
|
4814
|
+
|
|
4768
4815
|
elif self.project.arch.name == "AMD64":
|
|
4769
4816
|
# determine if the function uses rbp as a general purpose register or not
|
|
4770
4817
|
if addr == func_addr or 0 < addr - func_addr <= 0x20:
|
|
@@ -50,7 +50,7 @@ class CFGFastSoot(CFGFast):
|
|
|
50
50
|
self._initialize_cfg()
|
|
51
51
|
|
|
52
52
|
# Initialize variables used during analysis
|
|
53
|
-
self._pending_jobs = PendingJobs(self.
|
|
53
|
+
self._pending_jobs = PendingJobs(self.kb, self._deregister_analysis_job)
|
|
54
54
|
self._traced_addresses = set()
|
|
55
55
|
self._changed_functions = set()
|
|
56
56
|
self._updated_nonreturning_functions = set()
|
|
@@ -9,6 +9,7 @@ from .amd64_elf_got import AMD64ElfGotResolver
|
|
|
9
9
|
from .arm_elf_fast import ArmElfFastResolver
|
|
10
10
|
from .const_resolver import ConstantResolver
|
|
11
11
|
from .amd64_pe_iat import AMD64PeIatResolver
|
|
12
|
+
from .memload_resolver import MemoryLoadResolver
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
__all__ = (
|
|
@@ -17,6 +18,7 @@ __all__ = (
|
|
|
17
18
|
"ArmElfFastResolver",
|
|
18
19
|
"ConstantResolver",
|
|
19
20
|
"JumpTableResolver",
|
|
21
|
+
"MemoryLoadResolver",
|
|
20
22
|
"MipsElfFastResolver",
|
|
21
23
|
"MipsElfGotResolver",
|
|
22
24
|
"X86ElfPicPltResolver",
|
|
@@ -75,7 +75,31 @@ class ConstantResolver(IndirectJumpResolver):
|
|
|
75
75
|
|
|
76
76
|
vex_block = block.vex
|
|
77
77
|
if isinstance(vex_block.next, pyvex.expr.RdTmp):
|
|
78
|
-
|
|
78
|
+
tmp_stmt_idx, tmp_ins_addr = self._find_tmp_write_stmt_and_ins(vex_block, vex_block.next.tmp)
|
|
79
|
+
if tmp_stmt_idx is None or tmp_ins_addr is None:
|
|
80
|
+
return False, []
|
|
81
|
+
|
|
82
|
+
# first check: is it jumping to a target loaded from memory? if so, it should have been resolved by
|
|
83
|
+
# MemoryLoadResolver.
|
|
84
|
+
stmt = vex_block.statements[tmp_stmt_idx]
|
|
85
|
+
assert isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
86
|
+
if (
|
|
87
|
+
isinstance(stmt.data, pyvex.IRExpr.Load)
|
|
88
|
+
and isinstance(stmt.data.addr, pyvex.IRExpr.Const)
|
|
89
|
+
and stmt.data.result_size(vex_block.tyenv) == self.project.arch.bits
|
|
90
|
+
):
|
|
91
|
+
# well, if MemoryLoadResolver hasn't resolved it, we can try to resolve it here, or bail early because
|
|
92
|
+
# ConstantResolver won't help.
|
|
93
|
+
load_addr = stmt.data.addr.con.value
|
|
94
|
+
try:
|
|
95
|
+
value = self.project.loader.memory.unpack_word(load_addr, size=self.project.arch.bytes)
|
|
96
|
+
if isinstance(value, int) and self._is_target_valid(cfg, value):
|
|
97
|
+
return True, [value]
|
|
98
|
+
except KeyError:
|
|
99
|
+
pass
|
|
100
|
+
return False, []
|
|
101
|
+
|
|
102
|
+
# second check: what does the jump rely on? slice it back and see
|
|
79
103
|
b = Blade(
|
|
80
104
|
cfg.graph,
|
|
81
105
|
addr,
|
|
@@ -104,26 +128,25 @@ class ConstantResolver(IndirectJumpResolver):
|
|
|
104
128
|
block = self.project.factory.block(pred_addr, cross_insn_opt=True).vex
|
|
105
129
|
if stmt_idx != DEFAULT_STATEMENT:
|
|
106
130
|
stmt = block.statements[stmt_idx]
|
|
107
|
-
if
|
|
131
|
+
if (
|
|
132
|
+
isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
133
|
+
and isinstance(stmt.data, pyvex.IRExpr.Load)
|
|
134
|
+
and not isinstance(stmt.data.addr, pyvex.IRExpr.Const)
|
|
135
|
+
):
|
|
108
136
|
# loading from memory - unsupported
|
|
109
137
|
return False, []
|
|
110
138
|
break
|
|
111
139
|
|
|
112
140
|
_l.debug("ConstantResolver: Propagating for %r at %#x.", func, addr)
|
|
113
|
-
prop = self.project.analyses.
|
|
114
|
-
func
|
|
115
|
-
only_consts=True,
|
|
116
|
-
do_binops=True,
|
|
141
|
+
prop = self.project.analyses.FastConstantPropagation(
|
|
142
|
+
func,
|
|
117
143
|
vex_cross_insn_opt=False,
|
|
118
|
-
completed_funcs=cfg._completed_functions,
|
|
119
144
|
load_callback=PropagatorLoadCallback(self.project).propagator_load_callback,
|
|
120
|
-
cache_results=True,
|
|
121
|
-
key_prefix="cfg_intermediate",
|
|
122
145
|
)
|
|
123
146
|
|
|
124
147
|
replacements = prop.replacements
|
|
125
148
|
if replacements:
|
|
126
|
-
block_loc = CodeLocation(block.addr,
|
|
149
|
+
block_loc = CodeLocation(block.addr, tmp_stmt_idx, ins_addr=tmp_ins_addr)
|
|
127
150
|
tmp_var = vex_vars.VEXTmp(vex_block.next.tmp)
|
|
128
151
|
|
|
129
152
|
if exists_in_replacements(replacements, block_loc, tmp_var):
|
|
@@ -135,5 +158,18 @@ class ConstantResolver(IndirectJumpResolver):
|
|
|
135
158
|
and self._is_target_valid(cfg, resolved_tmp.args[0])
|
|
136
159
|
):
|
|
137
160
|
return True, [resolved_tmp.args[0]]
|
|
161
|
+
if isinstance(resolved_tmp, int) and self._is_target_valid(cfg, resolved_tmp):
|
|
162
|
+
return True, [resolved_tmp]
|
|
138
163
|
|
|
139
164
|
return False, []
|
|
165
|
+
|
|
166
|
+
@staticmethod
|
|
167
|
+
def _find_tmp_write_stmt_and_ins(vex_block, tmp: int) -> tuple[int | None, int | None]:
|
|
168
|
+
stmt_idx = None
|
|
169
|
+
for idx, stmt in enumerate(reversed(vex_block.statements)):
|
|
170
|
+
if isinstance(stmt, pyvex.IRStmt.IMark) and stmt_idx is not None:
|
|
171
|
+
ins_addr = stmt.addr + stmt.delta
|
|
172
|
+
return stmt_idx, ins_addr
|
|
173
|
+
if isinstance(stmt, pyvex.IRStmt.WrTmp) and stmt.tmp == tmp:
|
|
174
|
+
stmt_idx = len(vex_block.statements) - idx - 1
|
|
175
|
+
return None, None
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import cle
|
|
3
|
+
from angr.analyses.cfg.indirect_jump_resolvers import MemoryLoadResolver
|
|
3
4
|
|
|
4
5
|
from . import MipsElfFastResolver
|
|
5
6
|
from . import X86ElfPicPltResolver
|
|
@@ -19,6 +20,9 @@ DEFAULT_RESOLVERS = {
|
|
|
19
20
|
cle.PE: [
|
|
20
21
|
X86PeIatResolver,
|
|
21
22
|
],
|
|
23
|
+
cle.XBE: [
|
|
24
|
+
X86PeIatResolver,
|
|
25
|
+
],
|
|
22
26
|
},
|
|
23
27
|
"AMD64": {
|
|
24
28
|
cle.MetaELF: [
|
|
@@ -54,7 +58,7 @@ DEFAULT_RESOLVERS = {
|
|
|
54
58
|
ArmElfFastResolver,
|
|
55
59
|
]
|
|
56
60
|
},
|
|
57
|
-
"ALL": [JumpTableResolver, ConstantResolver],
|
|
61
|
+
"ALL": [MemoryLoadResolver, JumpTableResolver, ConstantResolver],
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
|
|
@@ -10,6 +10,7 @@ import functools
|
|
|
10
10
|
import pyvex
|
|
11
11
|
import claripy
|
|
12
12
|
from archinfo.arch_arm import is_arm_arch
|
|
13
|
+
from claripy.annotation import UninitializedAnnotation
|
|
13
14
|
|
|
14
15
|
from angr import sim_options as o
|
|
15
16
|
from angr import BP, BP_BEFORE, BP_AFTER
|
|
@@ -144,20 +145,22 @@ class ConstantValueManager:
|
|
|
144
145
|
|
|
145
146
|
__slots__ = (
|
|
146
147
|
"func",
|
|
148
|
+
"indirect_jump_addr",
|
|
147
149
|
"kb",
|
|
148
150
|
"mapping",
|
|
149
151
|
"project",
|
|
150
152
|
)
|
|
151
153
|
|
|
152
|
-
def __init__(self, project: Project, kb, func: Function):
|
|
154
|
+
def __init__(self, project: Project, kb, func: Function, ij_addr: int):
|
|
153
155
|
self.project = project
|
|
154
156
|
self.kb = kb
|
|
155
157
|
self.func = func
|
|
158
|
+
self.indirect_jump_addr = ij_addr
|
|
156
159
|
|
|
157
160
|
self.mapping: dict[Any, dict[Any, claripy.ast.Base]] | None = None
|
|
158
161
|
|
|
159
162
|
def reg_read_callback(self, state: SimState):
|
|
160
|
-
if
|
|
163
|
+
if self.mapping is None:
|
|
161
164
|
self._build_mapping()
|
|
162
165
|
assert self.mapping is not None
|
|
163
166
|
|
|
@@ -168,18 +171,54 @@ class ConstantValueManager:
|
|
|
168
171
|
reg_read_offset = reg_read_offset.args[0]
|
|
169
172
|
variable = VEXReg(reg_read_offset, state.inspect.reg_read_length)
|
|
170
173
|
if variable in self.mapping[codeloc]:
|
|
171
|
-
|
|
174
|
+
v = self.mapping[codeloc][variable]
|
|
175
|
+
if isinstance(v, int):
|
|
176
|
+
v = claripy.BVV(v, state.inspect.reg_read_length * state.arch.byte_width)
|
|
177
|
+
state.inspect.reg_read_expr = v
|
|
172
178
|
|
|
173
179
|
def _build_mapping(self):
|
|
174
180
|
# constant propagation
|
|
175
|
-
l.debug("JumpTable: Propagating for %r.", self.func)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
181
|
+
l.debug("JumpTable: Propagating for %r at %#x.", self.func, self.indirect_jump_addr)
|
|
182
|
+
|
|
183
|
+
# determine blocks to run FCP on
|
|
184
|
+
|
|
185
|
+
# - include at most three levels of successors from the entrypoint
|
|
186
|
+
startpoint = self.func.startpoint
|
|
187
|
+
blocks = set()
|
|
188
|
+
succs = [startpoint]
|
|
189
|
+
for _ in range(3):
|
|
190
|
+
new_succs = []
|
|
191
|
+
for node in succs:
|
|
192
|
+
if node in blocks:
|
|
193
|
+
continue
|
|
194
|
+
blocks.add(node)
|
|
195
|
+
if node.addr == self.indirect_jump_addr:
|
|
196
|
+
# stop at the indirect jump block
|
|
197
|
+
continue
|
|
198
|
+
new_succs += list(self.func.graph.successors(node))
|
|
199
|
+
succs = new_succs
|
|
200
|
+
if not succs:
|
|
201
|
+
break
|
|
202
|
+
|
|
203
|
+
# - include at most six levels of predecessors from the indirect jump block
|
|
204
|
+
ij_block = self.func.get_node(self.indirect_jump_addr)
|
|
205
|
+
preds = [ij_block]
|
|
206
|
+
for _ in range(6):
|
|
207
|
+
new_preds = []
|
|
208
|
+
for node in preds:
|
|
209
|
+
if node in blocks:
|
|
210
|
+
continue
|
|
211
|
+
blocks.add(node)
|
|
212
|
+
new_preds += list(self.func.graph.predecessors(node))
|
|
213
|
+
preds = new_preds
|
|
214
|
+
if not preds:
|
|
215
|
+
break
|
|
216
|
+
|
|
217
|
+
prop = self.project.analyses.FastConstantPropagation(
|
|
218
|
+
self.func,
|
|
219
|
+
blocks=blocks,
|
|
179
220
|
vex_cross_insn_opt=True,
|
|
180
221
|
load_callback=PropagatorLoadCallback(self.project).propagator_load_callback,
|
|
181
|
-
cache_results=True,
|
|
182
|
-
key_prefix="cfg_intermediate",
|
|
183
222
|
)
|
|
184
223
|
self.mapping = prop.replacements
|
|
185
224
|
|
|
@@ -853,7 +892,7 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
853
892
|
potential_call_table = jumpkind == "Ijk_Call" or self._sp_moved_up(block) or len(func.block_addrs_set) <= 5
|
|
854
893
|
# we only perform full-function propagation for jump tables or call tables in really small functions
|
|
855
894
|
if not potential_call_table or len(func.block_addrs_set) <= 5:
|
|
856
|
-
cv_manager = ConstantValueManager(self.project, cfg.kb, func)
|
|
895
|
+
cv_manager = ConstantValueManager(self.project, cfg.kb, func, addr)
|
|
857
896
|
else:
|
|
858
897
|
cv_manager = None
|
|
859
898
|
|
|
@@ -2131,7 +2170,7 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
2131
2170
|
read_addr = state.inspect.mem_read_address
|
|
2132
2171
|
cond = state.inspect.mem_read_condition
|
|
2133
2172
|
|
|
2134
|
-
if not isinstance(read_addr, int) and read_addr.
|
|
2173
|
+
if not isinstance(read_addr, int) and read_addr.has_annotation_type(UninitializedAnnotation) and cond is None:
|
|
2135
2174
|
# if this AST has been initialized before, just use the cached addr
|
|
2136
2175
|
cached_addr = self._cached_memread_addrs.get(read_addr, None)
|
|
2137
2176
|
if cached_addr is not None:
|
|
@@ -2402,6 +2441,3 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
2402
2441
|
if load_stmt_ids:
|
|
2403
2442
|
return [load_stmt_ids[-1]]
|
|
2404
2443
|
return []
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
from angr.analyses.propagator import PropagatorAnalysis
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
import pyvex
|
|
5
|
+
|
|
6
|
+
from .resolver import IndirectJumpResolver
|
|
7
|
+
|
|
8
|
+
_l = logging.getLogger(name=__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MemoryLoadResolver(IndirectJumpResolver):
|
|
12
|
+
"""
|
|
13
|
+
Resolve an indirect jump that looks like the following::
|
|
14
|
+
|
|
15
|
+
.text:
|
|
16
|
+
call off_3314A8
|
|
17
|
+
|
|
18
|
+
.data:
|
|
19
|
+
off_3314A8 dd offset sub_1E426F
|
|
20
|
+
|
|
21
|
+
This indirect jump resolver may not be the best solution for all cases (e.g., when the .data section can be
|
|
22
|
+
intentionally altered by the binary itself).
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, project):
|
|
26
|
+
super().__init__(project, timeless=True)
|
|
27
|
+
|
|
28
|
+
def filter(self, cfg, addr, func_addr, block, jumpkind):
|
|
29
|
+
return jumpkind in {"Ijk_Boring", "Ijk_Call"}
|
|
30
|
+
|
|
31
|
+
def resolve( # pylint:disable=unused-argument
|
|
32
|
+
self,
|
|
33
|
+
cfg,
|
|
34
|
+
addr: int,
|
|
35
|
+
func_addr: int,
|
|
36
|
+
block: pyvex.IRSB,
|
|
37
|
+
jumpkind: str,
|
|
38
|
+
func_graph_complete: bool = True,
|
|
39
|
+
**kwargs,
|
|
40
|
+
):
|
|
41
|
+
"""
|
|
42
|
+
:param cfg: CFG with specified function
|
|
43
|
+
:param addr: Address of indirect jump
|
|
44
|
+
:param func_addr: Address of function of indirect jump
|
|
45
|
+
:param block: Block of indirect jump (Block object)
|
|
46
|
+
:param jumpkind: VEX jumpkind (Ijk_Boring or Ijk_Call)
|
|
47
|
+
:return: Bool tuple with replacement address
|
|
48
|
+
"""
|
|
49
|
+
vex_block = block
|
|
50
|
+
if isinstance(vex_block.next, pyvex.expr.RdTmp):
|
|
51
|
+
tmp_stmt_idx, tmp_ins_addr = self._find_tmp_write_stmt_and_ins(vex_block, vex_block.next.tmp)
|
|
52
|
+
if tmp_stmt_idx is None or tmp_ins_addr is None:
|
|
53
|
+
return False, []
|
|
54
|
+
|
|
55
|
+
stmt = vex_block.statements[tmp_stmt_idx]
|
|
56
|
+
assert isinstance(stmt, pyvex.IRStmt.WrTmp)
|
|
57
|
+
if (
|
|
58
|
+
isinstance(stmt.data, pyvex.IRExpr.Load)
|
|
59
|
+
and isinstance(stmt.data.addr, pyvex.IRExpr.Const)
|
|
60
|
+
and stmt.data.result_size(vex_block.tyenv) == self.project.arch.bits
|
|
61
|
+
):
|
|
62
|
+
load_addr = stmt.data.addr.con.value
|
|
63
|
+
try:
|
|
64
|
+
value = self.project.loader.memory.unpack_word(load_addr, size=self.project.arch.bytes)
|
|
65
|
+
if isinstance(value, int) and self._is_target_valid(cfg, value):
|
|
66
|
+
return True, [value]
|
|
67
|
+
except KeyError:
|
|
68
|
+
return False, []
|
|
69
|
+
|
|
70
|
+
return False, []
|
|
71
|
+
|
|
72
|
+
@staticmethod
|
|
73
|
+
def _find_tmp_write_stmt_and_ins(vex_block, tmp: int) -> tuple[int | None, int | None]:
|
|
74
|
+
stmt_idx = None
|
|
75
|
+
for idx, stmt in enumerate(reversed(vex_block.statements)):
|
|
76
|
+
if isinstance(stmt, pyvex.IRStmt.IMark) and stmt_idx is not None:
|
|
77
|
+
ins_addr = stmt.addr + stmt.delta
|
|
78
|
+
return stmt_idx, ins_addr
|
|
79
|
+
if isinstance(stmt, pyvex.IRStmt.WrTmp) and stmt.tmp == tmp:
|
|
80
|
+
stmt_idx = len(vex_block.statements) - idx - 1
|
|
81
|
+
return None, None
|