angr 9.2.136__py3-none-manylinux2014_x86_64.whl → 9.2.137__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/calling_convention/calling_convention.py +2 -1
- angr/analyses/calling_convention/fact_collector.py +10 -2
- angr/analyses/cfg/cfg_base.py +3 -33
- angr/analyses/cfg/cfg_emulated.py +0 -103
- angr/analyses/cfg/cfg_fast.py +28 -12
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +15 -0
- angr/analyses/class_identifier.py +1 -2
- angr/analyses/complete_calling_conventions.py +3 -0
- angr/analyses/decompiler/ail_simplifier.py +12 -1
- angr/analyses/decompiler/block_simplifier.py +2 -2
- angr/analyses/decompiler/ccall_rewriters/__init__.py +2 -0
- angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
- angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +69 -0
- angr/analyses/decompiler/clinic.py +77 -65
- angr/analyses/decompiler/condition_processor.py +2 -0
- angr/analyses/decompiler/decompiler.py +1 -0
- angr/analyses/decompiler/dephication/dephication_base.py +2 -0
- angr/analyses/decompiler/dephication/rewriting_engine.py +8 -6
- angr/analyses/decompiler/dephication/seqnode_dephication.py +10 -1
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +1 -2
- angr/analyses/decompiler/sequence_walker.py +6 -2
- angr/analyses/decompiler/ssailification/rewriting.py +11 -1
- angr/analyses/decompiler/ssailification/rewriting_engine.py +56 -19
- angr/analyses/decompiler/ssailification/ssailification.py +13 -3
- angr/analyses/decompiler/ssailification/traversal.py +28 -2
- angr/analyses/decompiler/ssailification/traversal_state.py +6 -1
- angr/analyses/decompiler/structured_codegen/c.py +44 -21
- angr/analyses/decompiler/structuring/phoenix.py +117 -14
- angr/analyses/decompiler/utils.py +113 -8
- angr/analyses/reaching_definitions/function_handler.py +1 -1
- angr/analyses/s_liveness.py +5 -1
- angr/analyses/s_propagator.py +25 -4
- angr/analyses/s_reaching_definitions/s_rda_model.py +2 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +20 -1
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +11 -1
- angr/analyses/stack_pointer_tracker.py +26 -16
- angr/analyses/variable_recovery/engine_ail.py +19 -7
- angr/analyses/variable_recovery/engine_base.py +16 -14
- angr/analyses/variable_recovery/engine_vex.py +2 -2
- angr/analyses/variable_recovery/variable_recovery_fast.py +22 -1
- angr/block.py +59 -20
- angr/engines/pcode/emulate.py +1 -1
- angr/engines/pcode/lifter.py +31 -18
- angr/engines/soot/expressions/__init__.py +2 -4
- angr/engines/soot/statements/__init__.py +1 -2
- angr/engines/soot/values/__init__.py +1 -2
- angr/engines/successors.py +11 -6
- angr/engines/vex/lifter.py +9 -6
- angr/flirt/build_sig.py +8 -15
- angr/knowledge_plugins/functions/function.py +0 -6
- angr/knowledge_plugins/functions/soot_function.py +5 -8
- angr/knowledge_plugins/variables/variable_manager.py +16 -10
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/METADATA +7 -7
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/RECORD +59 -58
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/WHEEL +1 -1
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/LICENSE +0 -0
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/entry_points.txt +0 -0
- {angr-9.2.136.dist-info → angr-9.2.137.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
|
@@ -436,7 +436,8 @@ class CallingConventionAnalysis(Analysis):
|
|
|
436
436
|
if caller.is_simprocedure or caller.is_alignment:
|
|
437
437
|
# do not analyze SimProcedures or alignment stubs
|
|
438
438
|
continue
|
|
439
|
-
|
|
439
|
+
if src.instruction_addrs:
|
|
440
|
+
call_sites_by_function[caller].append((src.addr, src.instruction_addrs[-1]))
|
|
440
441
|
|
|
441
442
|
call_sites_by_function_list = sorted(call_sites_by_function.items(), key=lambda x: x[0].addr)[
|
|
442
443
|
:max_analyzing_callsites
|
|
@@ -276,13 +276,21 @@ class FactCollector(Analysis):
|
|
|
276
276
|
call_succ, ret_succ = None, None
|
|
277
277
|
for _, succ, data in func_graph.out_edges(node, data=True):
|
|
278
278
|
edge_type = data.get("type")
|
|
279
|
+
outside = data.get("outside", False)
|
|
279
280
|
if succ not in traversed and depth + 1 <= self._max_depth:
|
|
280
281
|
if edge_type == "fake_return":
|
|
281
282
|
ret_succ = succ
|
|
282
|
-
elif edge_type == "transition":
|
|
283
|
+
elif edge_type == "transition" and not outside:
|
|
283
284
|
successor_added = True
|
|
284
285
|
queue.append((depth + 1, state.copy(), succ, None))
|
|
285
|
-
elif edge_type == "call":
|
|
286
|
+
elif edge_type == "call" or (edge_type == "transition" and outside):
|
|
287
|
+
# a call or a tail-call
|
|
288
|
+
if not isinstance(succ, Function):
|
|
289
|
+
if self.kb.functions.contains_addr(succ.addr):
|
|
290
|
+
succ = self.kb.functions.get_by_addr(succ.addr)
|
|
291
|
+
else:
|
|
292
|
+
# not sure who we are calling
|
|
293
|
+
continue
|
|
286
294
|
call_succ = succ
|
|
287
295
|
if call_succ is not None:
|
|
288
296
|
successor_added = True
|
angr/analyses/cfg/cfg_base.py
CHANGED
|
@@ -2520,18 +2520,17 @@ class CFGBase(Analysis):
|
|
|
2520
2520
|
#
|
|
2521
2521
|
|
|
2522
2522
|
@staticmethod
|
|
2523
|
-
def _is_noop_block(arch: archinfo.Arch, block):
|
|
2523
|
+
def _is_noop_block(arch: archinfo.Arch, block) -> bool:
|
|
2524
2524
|
"""
|
|
2525
2525
|
Check if the block is a no-op block by checking VEX statements.
|
|
2526
2526
|
|
|
2527
2527
|
:param arch: An architecture descriptor.
|
|
2528
2528
|
:param block: The VEX block instance.
|
|
2529
2529
|
:return: True if the entire block is a single-byte or multi-byte nop instruction, False otherwise.
|
|
2530
|
-
:rtype: bool
|
|
2531
2530
|
"""
|
|
2532
2531
|
|
|
2533
2532
|
if arch.name == "X86" or arch.name == "AMD64":
|
|
2534
|
-
if set(block.bytes) == {
|
|
2533
|
+
if set(block.bytes) == {0x90}:
|
|
2535
2534
|
return True
|
|
2536
2535
|
elif arch.name == "MIPS32":
|
|
2537
2536
|
if arch.memory_endness == "Iend_BE":
|
|
@@ -2577,36 +2576,7 @@ class CFGBase(Analysis):
|
|
|
2577
2576
|
if THUMB_NOOPS.issuperset(insns):
|
|
2578
2577
|
return True
|
|
2579
2578
|
|
|
2580
|
-
|
|
2581
|
-
# the block is a noop block if it only has IMark statements **and** it jumps to its immediate successor. VEX
|
|
2582
|
-
# will generate such blocks when opt_level==1 and cross_insn_opt is True
|
|
2583
|
-
fallthrough_addr = block.addr + block.size
|
|
2584
|
-
next_ = block.vex.next
|
|
2585
|
-
if (
|
|
2586
|
-
isinstance(next_, pyvex.IRExpr.Const)
|
|
2587
|
-
and next_.con.value == fallthrough_addr
|
|
2588
|
-
and all((type(stmt) is pyvex.IRStmt.IMark) for stmt in block.vex.statements)
|
|
2589
|
-
):
|
|
2590
|
-
return True
|
|
2591
|
-
|
|
2592
|
-
# the block is a noop block if it only has IMark statements and IP-setting statements that set the IP to the
|
|
2593
|
-
# next location. VEX will generate such blocks when opt_level==1 and cross_insn_opt is False
|
|
2594
|
-
ip_offset = arch.ip_offset
|
|
2595
|
-
if (
|
|
2596
|
-
all(
|
|
2597
|
-
(type(stmt) is pyvex.IRStmt.IMark or (type(stmt) is pyvex.IRStmt.Put and stmt.offset == ip_offset))
|
|
2598
|
-
for stmt in block.vex.statements
|
|
2599
|
-
)
|
|
2600
|
-
and block.vex.statements
|
|
2601
|
-
):
|
|
2602
|
-
last_stmt = block.vex.statements[-1]
|
|
2603
|
-
if (
|
|
2604
|
-
isinstance(last_stmt, pyvex.IRStmt.IMark)
|
|
2605
|
-
and isinstance(next_, pyvex.IRExpr.Const)
|
|
2606
|
-
and next_.con.value == fallthrough_addr
|
|
2607
|
-
):
|
|
2608
|
-
return True
|
|
2609
|
-
return False
|
|
2579
|
+
return block.vex_nostmt.is_noop_block
|
|
2610
2580
|
|
|
2611
2581
|
@staticmethod
|
|
2612
2582
|
def _is_noop_insn(insn):
|
|
@@ -3208,109 +3208,6 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
3208
3208
|
# Update loop backedges and graph
|
|
3209
3209
|
self._loop_back_edges = list(itertools.chain.from_iterable(loop.continue_edges for loop in loop_finder.loops))
|
|
3210
3210
|
|
|
3211
|
-
# Private methods - function/procedure/subroutine analysis
|
|
3212
|
-
# Including calling convention, function arguments, etc.
|
|
3213
|
-
|
|
3214
|
-
def _refine_function_arguments(self, func, callsites):
|
|
3215
|
-
"""
|
|
3216
|
-
|
|
3217
|
-
:param func:
|
|
3218
|
-
:param callsites:
|
|
3219
|
-
:return:
|
|
3220
|
-
"""
|
|
3221
|
-
|
|
3222
|
-
for i, c in enumerate(callsites):
|
|
3223
|
-
# Execute one block ahead of the callsite, and execute one basic block after the callsite
|
|
3224
|
-
# In this process, the following tasks are performed:
|
|
3225
|
-
# - Record registers/stack variables that are modified
|
|
3226
|
-
# - Record the change of the stack pointer
|
|
3227
|
-
# - Check if the return value is used immediately
|
|
3228
|
-
# We assume that the stack is balanced before and after the call (you can have caller clean-up of course).
|
|
3229
|
-
# Any abnormal behaviors will be logged.
|
|
3230
|
-
# Hopefully this approach will allow us to have a better understanding of parameters of those function
|
|
3231
|
-
# stubs and function proxies.
|
|
3232
|
-
|
|
3233
|
-
if c.simprocedure_name is not None:
|
|
3234
|
-
# Skip all SimProcedures
|
|
3235
|
-
continue
|
|
3236
|
-
|
|
3237
|
-
l.debug("Refining %s at 0x%x (%d/%d).", repr(func), c.addr, i, len(callsites))
|
|
3238
|
-
|
|
3239
|
-
# Get a basic block ahead of the callsite
|
|
3240
|
-
blocks_ahead = [c]
|
|
3241
|
-
|
|
3242
|
-
# the block after
|
|
3243
|
-
blocks_after = []
|
|
3244
|
-
successors = self.get_successors_and_jumpkind(c, excluding_fakeret=False)
|
|
3245
|
-
for s, jk in successors:
|
|
3246
|
-
if jk == "Ijk_FakeRet":
|
|
3247
|
-
blocks_after = [s]
|
|
3248
|
-
break
|
|
3249
|
-
|
|
3250
|
-
regs_overwritten = set()
|
|
3251
|
-
stack_overwritten = set()
|
|
3252
|
-
regs_read = set()
|
|
3253
|
-
regs_written = set()
|
|
3254
|
-
|
|
3255
|
-
try:
|
|
3256
|
-
# Execute the predecessor
|
|
3257
|
-
path = self.project.factory.path(
|
|
3258
|
-
self.project.factory.blank_state(mode="fastpath", addr=blocks_ahead[0].addr)
|
|
3259
|
-
)
|
|
3260
|
-
path.step()
|
|
3261
|
-
all_successors = path.next_run.successors + path.next_run.unsat_successors
|
|
3262
|
-
if not all_successors:
|
|
3263
|
-
continue
|
|
3264
|
-
|
|
3265
|
-
suc = all_successors[0]
|
|
3266
|
-
se = suc.solver
|
|
3267
|
-
# Examine the path log
|
|
3268
|
-
actions = suc.history.recent_actions
|
|
3269
|
-
sp = se.eval_one(suc.regs.sp, default=0) + self.project.arch.call_sp_fix
|
|
3270
|
-
for ac in actions:
|
|
3271
|
-
if ac.type == "reg" and ac.action == "write":
|
|
3272
|
-
regs_overwritten.add(ac.offset)
|
|
3273
|
-
elif ac.type == "mem" and ac.action == "write":
|
|
3274
|
-
addr = se.eval_one(ac.addr.ast, default=0)
|
|
3275
|
-
if (self.project.arch.call_pushes_ret and addr >= sp + self.project.arch.bytes) or (
|
|
3276
|
-
not self.project.arch.call_pushes_ret and addr >= sp
|
|
3277
|
-
):
|
|
3278
|
-
offset = addr - sp
|
|
3279
|
-
stack_overwritten.add(offset)
|
|
3280
|
-
|
|
3281
|
-
func.prepared_registers.add(tuple(regs_overwritten))
|
|
3282
|
-
func.prepared_stack_variables.add(tuple(stack_overwritten))
|
|
3283
|
-
|
|
3284
|
-
except (SimError, AngrError):
|
|
3285
|
-
pass
|
|
3286
|
-
|
|
3287
|
-
try:
|
|
3288
|
-
if blocks_after:
|
|
3289
|
-
path = self.project.factory.path(
|
|
3290
|
-
self.project.factory.blank_state(mode="fastpath", addr=blocks_after[0].addr)
|
|
3291
|
-
)
|
|
3292
|
-
path.step()
|
|
3293
|
-
all_successors = path.next_run.successors + path.next_run.unsat_successors
|
|
3294
|
-
if not all_successors:
|
|
3295
|
-
continue
|
|
3296
|
-
|
|
3297
|
-
suc = all_successors[0]
|
|
3298
|
-
actions = suc.history.recent_actions
|
|
3299
|
-
for ac in actions:
|
|
3300
|
-
if ac.type == "reg" and ac.action == "read" and ac.offset not in regs_written:
|
|
3301
|
-
regs_read.add(ac.offset)
|
|
3302
|
-
elif ac.type == "reg" and ac.action == "write":
|
|
3303
|
-
regs_written.add(ac.offset)
|
|
3304
|
-
|
|
3305
|
-
# Filter registers, remove unnecessary registers from the set
|
|
3306
|
-
# regs_overwritten = self.project.arch.argument_registers.intersection(regs_overwritten)
|
|
3307
|
-
regs_read = self.project.arch.argument_registers.intersection(regs_read)
|
|
3308
|
-
|
|
3309
|
-
func.registers_read_afterwards.add(tuple(regs_read))
|
|
3310
|
-
|
|
3311
|
-
except (SimError, AngrError):
|
|
3312
|
-
pass
|
|
3313
|
-
|
|
3314
3211
|
# Private methods - dominators and post-dominators
|
|
3315
3212
|
|
|
3316
3213
|
def _immediate_dominators(self, node, target_graph=None, reverse_graph=False):
|
angr/analyses/cfg/cfg_fast.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# pylint:disable=superfluous-parens,too-many-boolean-expressions,line-too-long
|
|
2
2
|
from __future__ import annotations
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
3
4
|
import itertools
|
|
4
5
|
import logging
|
|
5
6
|
import math
|
|
@@ -52,6 +53,10 @@ from .cfg_arch_options import CFGArchOptions
|
|
|
52
53
|
from .cfg_base import CFGBase
|
|
53
54
|
from .indirect_jump_resolvers.jumptable import JumpTableResolver
|
|
54
55
|
|
|
56
|
+
if TYPE_CHECKING:
|
|
57
|
+
from angr.block import Block
|
|
58
|
+
from angr.engines.pcode.lifter import IRSB as PcodeIRSB
|
|
59
|
+
|
|
55
60
|
|
|
56
61
|
VEX_IRSB_MAX_SIZE = 400
|
|
57
62
|
|
|
@@ -825,10 +830,10 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
825
830
|
#
|
|
826
831
|
# Variables used during analysis
|
|
827
832
|
#
|
|
828
|
-
self._pending_jobs = None
|
|
829
|
-
self._traced_addresses = None
|
|
833
|
+
self._pending_jobs = None # type:ignore
|
|
834
|
+
self._traced_addresses = None # type:ignore
|
|
830
835
|
self._function_returns = None
|
|
831
|
-
self._function_exits = None
|
|
836
|
+
self._function_exits = None # type:ignore
|
|
832
837
|
self._gp_value: int | None = None
|
|
833
838
|
self._ro_region_cdata_cache: list | None = None
|
|
834
839
|
self._job_ctr = 0
|
|
@@ -872,7 +877,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
872
877
|
if size is None:
|
|
873
878
|
size = len(data)
|
|
874
879
|
|
|
875
|
-
data = bytes(pyvex.ffi.buffer(data, size))
|
|
880
|
+
data = bytes(pyvex.ffi.buffer(data, size)) # type:ignore
|
|
876
881
|
for x in range(256):
|
|
877
882
|
p_x = float(data.count(x)) / size
|
|
878
883
|
if p_x > 0:
|
|
@@ -1229,7 +1234,9 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1229
1234
|
# umm now it's probably code
|
|
1230
1235
|
break
|
|
1231
1236
|
|
|
1232
|
-
instr_alignment = self.
|
|
1237
|
+
instr_alignment = self.project.arch.instruction_alignment
|
|
1238
|
+
if not instr_alignment:
|
|
1239
|
+
instr_alignment = 1
|
|
1233
1240
|
if start_addr % instr_alignment > 0:
|
|
1234
1241
|
# occupy those few bytes
|
|
1235
1242
|
size = instr_alignment - (start_addr % instr_alignment)
|
|
@@ -1286,7 +1293,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1286
1293
|
nodecode_bytes_ratio = (
|
|
1287
1294
|
0.0 if self._next_addr is None else self._nodecode_bytes_ratio(self._next_addr, self._nodecode_window_size)
|
|
1288
1295
|
)
|
|
1289
|
-
if nodecode_bytes_ratio >= self._nodecode_threshold:
|
|
1296
|
+
if nodecode_bytes_ratio >= self._nodecode_threshold and self._next_addr is not None:
|
|
1290
1297
|
next_allowed_addr = self._next_addr + self._nodecode_step
|
|
1291
1298
|
else:
|
|
1292
1299
|
next_allowed_addr = 0
|
|
@@ -1313,6 +1320,9 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1313
1320
|
return job.addr
|
|
1314
1321
|
|
|
1315
1322
|
def _pre_analysis(self):
|
|
1323
|
+
# Create a read-only memory view in loader for faster data loading
|
|
1324
|
+
self.project.loader.gen_ro_memview()
|
|
1325
|
+
|
|
1316
1326
|
# Call _initialize_cfg() before self.functions is used.
|
|
1317
1327
|
self._initialize_cfg()
|
|
1318
1328
|
|
|
@@ -1757,6 +1767,9 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1757
1767
|
|
|
1758
1768
|
CFGBase._post_analysis(self)
|
|
1759
1769
|
|
|
1770
|
+
# drop the read-only memory view in loader
|
|
1771
|
+
self.project.loader.discard_ro_memview()
|
|
1772
|
+
|
|
1760
1773
|
# Clean up
|
|
1761
1774
|
self._traced_addresses = None
|
|
1762
1775
|
self._lifter_deregister_readonly_regions()
|
|
@@ -2926,7 +2939,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
2926
2939
|
if v is not None:
|
|
2927
2940
|
tmps[stmt.tmp] = v
|
|
2928
2941
|
|
|
2929
|
-
elif type(stmt.data)
|
|
2942
|
+
elif type(stmt.data) is pyvex.IRExpr.Binop: # pylint: disable=unidiomatic-typecheck
|
|
2930
2943
|
# rip-related addressing
|
|
2931
2944
|
if stmt.data.op in ("Iop_Add32", "Iop_Add64"):
|
|
2932
2945
|
if all(type(arg) is pyvex.expr.Const for arg in stmt.data.args):
|
|
@@ -4412,8 +4425,8 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
4412
4425
|
|
|
4413
4426
|
# Let's try to create the pyvex IRSB directly, since it's much faster
|
|
4414
4427
|
nodecode = False
|
|
4415
|
-
irsb = None
|
|
4416
|
-
lifted_block = None
|
|
4428
|
+
irsb: pyvex.IRSB | PcodeIRSB | None = None
|
|
4429
|
+
lifted_block: Block = None # type:ignore
|
|
4417
4430
|
try:
|
|
4418
4431
|
lifted_block = self._lift(
|
|
4419
4432
|
addr,
|
|
@@ -4427,10 +4440,13 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
4427
4440
|
except SimTranslationError:
|
|
4428
4441
|
nodecode = True
|
|
4429
4442
|
|
|
4430
|
-
irsb_string: bytes =
|
|
4443
|
+
irsb_string: bytes = b""
|
|
4444
|
+
lifted_block_bytes = lifted_block.bytes if lifted_block.bytes is not None else b""
|
|
4445
|
+
if lifted_block is not None:
|
|
4446
|
+
irsb_string = lifted_block_bytes[: irsb.size] if irsb is not None else lifted_block_bytes
|
|
4431
4447
|
|
|
4432
4448
|
# special logic during the complete scanning phase
|
|
4433
|
-
if cfg_job.job_type == CFGJobType.COMPLETE_SCANNING and is_arm_arch(self.project.arch):
|
|
4449
|
+
if cfg_job.job_type == CFGJobType.COMPLETE_SCANNING and is_arm_arch(self.project.arch) and irsb is not None:
|
|
4434
4450
|
# it's way too easy to incorrectly disassemble THUMB code contains 0x4f as ARM code svc?? #????
|
|
4435
4451
|
# if we get a single block that getting decoded to svc?? under ARM mode, we treat it as nodecode
|
|
4436
4452
|
if (
|
|
@@ -4468,7 +4484,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
4468
4484
|
except SimTranslationError:
|
|
4469
4485
|
nodecode = True
|
|
4470
4486
|
|
|
4471
|
-
irsb_string
|
|
4487
|
+
irsb_string = lifted_block.bytes[: irsb.size] if irsb is not None else lifted_block.bytes
|
|
4472
4488
|
|
|
4473
4489
|
if not (nodecode or irsb.size == 0 or irsb.jumpkind == "Ijk_NoDecode"):
|
|
4474
4490
|
# it is decodeable
|
|
@@ -505,6 +505,21 @@ class JumpTableProcessor(
|
|
|
505
505
|
return self._top(expr.result_size(self.tyenv))
|
|
506
506
|
return v
|
|
507
507
|
|
|
508
|
+
@binop_handler
|
|
509
|
+
def _handle_binop_And(self, expr):
|
|
510
|
+
arg0 = self._expr(expr.args[0])
|
|
511
|
+
if (
|
|
512
|
+
isinstance(arg0, claripy.ast.BV)
|
|
513
|
+
and self._is_registeroffset(arg0)
|
|
514
|
+
and isinstance(expr.args[1], pyvex.IRExpr.Const)
|
|
515
|
+
):
|
|
516
|
+
mask_value = expr.args[1].con.value
|
|
517
|
+
if mask_value in {1, 3, 7, 15, 31, 63, 127, 255}:
|
|
518
|
+
# 1cbbf108f44c8f4babde546d26425ca5340dccf878d306b90eb0fbec2f83ab51:0x40bd1b
|
|
519
|
+
self.state.is_jumptable = True
|
|
520
|
+
return arg0 & mask_value
|
|
521
|
+
return self._top(expr.result_size(self.tyenv))
|
|
522
|
+
|
|
508
523
|
@binop_handler
|
|
509
524
|
def _handle_binop_CmpLE(self, expr):
|
|
510
525
|
return self._handle_Comparison(*expr.args)
|
|
@@ -30,8 +30,7 @@ class ClassIdentifier(Analysis):
|
|
|
30
30
|
continue
|
|
31
31
|
col_ind = func.demangled_name.rfind("::")
|
|
32
32
|
class_name = func.demangled_name[:col_ind]
|
|
33
|
-
|
|
34
|
-
class_name = class_name[len("non-virtual thunk for ") :]
|
|
33
|
+
class_name = class_name.removeprefix("non-virtual thunk for ")
|
|
35
34
|
if col_ind != -1:
|
|
36
35
|
if class_name not in self.classes:
|
|
37
36
|
ctor = False
|
|
@@ -208,6 +208,7 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
208
208
|
self._update_progress(percentage, text=f"{idx + 1}/{total_funcs} - {func.demangled_name}")
|
|
209
209
|
if self._low_priority:
|
|
210
210
|
self._release_gil(idx + 1, 10, 0.000001)
|
|
211
|
+
self._finish_progress()
|
|
211
212
|
|
|
212
213
|
else:
|
|
213
214
|
self._remaining_funcs.value = len(self._func_addrs)
|
|
@@ -298,6 +299,8 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
298
299
|
for proc in procs:
|
|
299
300
|
proc.join()
|
|
300
301
|
|
|
302
|
+
self._finish_progress()
|
|
303
|
+
|
|
301
304
|
def _worker_routine(self, worker_id: int, initializer: Initializer):
|
|
302
305
|
initializer.initialize()
|
|
303
306
|
idx = 0
|
|
@@ -207,9 +207,11 @@ class AILSimplifier(Analysis):
|
|
|
207
207
|
# Computing reaching definitions or return the cached one
|
|
208
208
|
if self._reaching_definitions is not None:
|
|
209
209
|
return self._reaching_definitions
|
|
210
|
+
func_args = {vvar for vvar, _ in self._arg_vvars.values()} if self._arg_vvars else set()
|
|
210
211
|
rd = self.project.analyses.SReachingDefinitions(
|
|
211
212
|
subject=self.func,
|
|
212
213
|
func_graph=self.func_graph,
|
|
214
|
+
func_args=func_args,
|
|
213
215
|
# use_callee_saved_regs_at_return=self._use_callee_saved_regs_at_return,
|
|
214
216
|
# track_tmps=True,
|
|
215
217
|
).model
|
|
@@ -220,9 +222,11 @@ class AILSimplifier(Analysis):
|
|
|
220
222
|
# Propagate expressions or return the existing result
|
|
221
223
|
if self._propagator is not None:
|
|
222
224
|
return self._propagator
|
|
223
|
-
|
|
225
|
+
func_args = {vvar for vvar, _ in self._arg_vvars.values()} if self._arg_vvars else set()
|
|
226
|
+
prop = self.project.analyses[SPropagatorAnalysis].prep(fail_fast=self._fail_fast)(
|
|
224
227
|
subject=self.func,
|
|
225
228
|
func_graph=self.func_graph,
|
|
229
|
+
func_args=func_args,
|
|
226
230
|
# gp=self._gp,
|
|
227
231
|
only_consts=self._only_consts,
|
|
228
232
|
)
|
|
@@ -898,6 +902,13 @@ class AILSimplifier(Analysis):
|
|
|
898
902
|
|
|
899
903
|
to_replace_def = the_def
|
|
900
904
|
|
|
905
|
+
# check: the definition of expression being replaced should not be a phi variable
|
|
906
|
+
if (
|
|
907
|
+
isinstance(to_replace_def.atom, atoms.VirtualVariable)
|
|
908
|
+
and to_replace_def.atom.varid in rd.phi_vvar_ids
|
|
909
|
+
):
|
|
910
|
+
continue
|
|
911
|
+
|
|
901
912
|
# find all uses of this definition
|
|
902
913
|
# we make a copy of the set since we may touch the set (uses) when replacing expressions
|
|
903
914
|
all_uses: set[tuple[CodeLocation, Any]] = set(rd.get_vvar_uses_with_expr(to_replace_def.atom))
|
|
@@ -141,7 +141,7 @@ class BlockSimplifier(Analysis):
|
|
|
141
141
|
|
|
142
142
|
def _compute_propagation(self, block) -> SPropagatorAnalysis:
|
|
143
143
|
if self._propagator is None:
|
|
144
|
-
self._propagator = self.project.analyses[SPropagatorAnalysis].prep()(
|
|
144
|
+
self._propagator = self.project.analyses[SPropagatorAnalysis].prep(fail_fast=self._fail_fast)(
|
|
145
145
|
subject=block,
|
|
146
146
|
func_addr=self.func_addr,
|
|
147
147
|
stack_pointer_tracker=self._stack_pointer_tracker,
|
|
@@ -152,7 +152,7 @@ class BlockSimplifier(Analysis):
|
|
|
152
152
|
if self._reaching_definitions is None:
|
|
153
153
|
self._reaching_definitions = (
|
|
154
154
|
self.project.analyses[SReachingDefinitionsAnalysis]
|
|
155
|
-
.prep()(
|
|
155
|
+
.prep(fail_fast=self._fail_fast)(
|
|
156
156
|
subject=block,
|
|
157
157
|
track_tmps=True,
|
|
158
158
|
func_addr=self.func_addr,
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from ailment import Expr
|
|
4
|
+
|
|
5
|
+
from angr.engines.vex.claripy.ccall import data
|
|
6
|
+
from .rewriter_base import CCallRewriterBase
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
X86_CondTypes = data["X86"]["CondTypes"]
|
|
10
|
+
X86_OpTypes = data["X86"]["OpTypes"]
|
|
11
|
+
X86_CondBitMasks = data["X86"]["CondBitMasks"]
|
|
12
|
+
X86_CondBitOffsets = data["X86"]["CondBitOffsets"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class X86CCallRewriter(CCallRewriterBase):
|
|
16
|
+
"""
|
|
17
|
+
Implements VEX ccall rewriter for X86.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__slots__ = ()
|
|
21
|
+
|
|
22
|
+
def _rewrite(self, ccall: Expr.VEXCCallExpression) -> Expr.Expression | None:
|
|
23
|
+
if ccall.callee == "x86g_calculate_condition":
|
|
24
|
+
cond = ccall.operands[0]
|
|
25
|
+
op = ccall.operands[1]
|
|
26
|
+
dep_1 = ccall.operands[2]
|
|
27
|
+
dep_2 = ccall.operands[3]
|
|
28
|
+
if isinstance(cond, Expr.Const) and isinstance(op, Expr.Const):
|
|
29
|
+
cond_v = cond.value
|
|
30
|
+
op_v = op.value
|
|
31
|
+
if cond_v == X86_CondTypes["CondLE"]: # noqa: SIM102
|
|
32
|
+
if op_v in {
|
|
33
|
+
X86_OpTypes["G_CC_OP_SUBB"],
|
|
34
|
+
X86_OpTypes["G_CC_OP_SUBW"],
|
|
35
|
+
X86_OpTypes["G_CC_OP_SUBL"],
|
|
36
|
+
}:
|
|
37
|
+
# dep_1 <=s dep_2
|
|
38
|
+
dep_1 = self._fix_size(
|
|
39
|
+
dep_1,
|
|
40
|
+
op_v,
|
|
41
|
+
X86_OpTypes["G_CC_OP_SUBB"],
|
|
42
|
+
X86_OpTypes["G_CC_OP_SUBW"],
|
|
43
|
+
ccall.tags,
|
|
44
|
+
)
|
|
45
|
+
dep_2 = self._fix_size(
|
|
46
|
+
dep_2,
|
|
47
|
+
op_v,
|
|
48
|
+
X86_OpTypes["G_CC_OP_SUBB"],
|
|
49
|
+
X86_OpTypes["G_CC_OP_SUBW"],
|
|
50
|
+
ccall.tags,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
r = Expr.BinaryOp(ccall.idx, "CmpLE", (dep_1, dep_2), True, **ccall.tags)
|
|
54
|
+
return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def _fix_size(expr, op_v: int, type_8bit, type_16bit, tags):
|
|
59
|
+
if op_v == type_8bit:
|
|
60
|
+
bits = 8
|
|
61
|
+
elif op_v == type_16bit:
|
|
62
|
+
bits = 16
|
|
63
|
+
else:
|
|
64
|
+
bits = 32
|
|
65
|
+
if bits < 32:
|
|
66
|
+
if isinstance(expr, Expr.Const):
|
|
67
|
+
return Expr.Const(expr.idx, None, expr.value & ((1 << bits) - 1), bits, **tags)
|
|
68
|
+
return Expr.Convert(None, 32, bits, False, expr, **tags)
|
|
69
|
+
return expr
|