angr 9.2.134__py3-none-macosx_10_9_x86_64.whl → 9.2.135__py3-none-macosx_10_9_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 +2 -1
- angr/analyses/calling_convention/__init__.py +6 -0
- angr/analyses/{calling_convention.py → calling_convention/calling_convention.py} +28 -61
- angr/analyses/calling_convention/fact_collector.py +503 -0
- angr/analyses/calling_convention/utils.py +57 -0
- angr/analyses/complete_calling_conventions.py +32 -3
- angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +0 -6
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +1 -6
- 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/variable_recovery/engine_vex.py +5 -0
- angr/calling_conventions.py +12 -4
- angr/knowledge_plugins/functions/function.py +4 -4
- angr/knowledge_plugins/functions/function_manager.py +6 -0
- angr/lib/angr_native.dylib +0 -0
- angr/utils/bits.py +13 -0
- {angr-9.2.134.dist-info → angr-9.2.135.dist-info}/METADATA +6 -6
- {angr-9.2.134.dist-info → angr-9.2.135.dist-info}/RECORD +23 -20
- {angr-9.2.134.dist-info → angr-9.2.135.dist-info}/LICENSE +0 -0
- {angr-9.2.134.dist-info → angr-9.2.135.dist-info}/WHEEL +0 -0
- {angr-9.2.134.dist-info → angr-9.2.135.dist-info}/entry_points.txt +0 -0
- {angr-9.2.134.dist-info → angr-9.2.135.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
angr/analyses/__init__.py
CHANGED
|
@@ -30,7 +30,7 @@ from .variable_recovery import VariableRecovery, VariableRecoveryFast
|
|
|
30
30
|
from .identifier import Identifier
|
|
31
31
|
from .callee_cleanup_finder import CalleeCleanupFinder
|
|
32
32
|
from .reaching_definitions import ReachingDefinitionsAnalysis
|
|
33
|
-
from .calling_convention import CallingConventionAnalysis
|
|
33
|
+
from .calling_convention import CallingConventionAnalysis, FactCollector
|
|
34
34
|
from .code_tagging import CodeTagging
|
|
35
35
|
from .stack_pointer_tracker import StackPointerTracker
|
|
36
36
|
from .dominance_frontier import DominanceFrontier
|
|
@@ -84,6 +84,7 @@ __all__ = (
|
|
|
84
84
|
"Decompiler",
|
|
85
85
|
"Disassembly",
|
|
86
86
|
"DominanceFrontier",
|
|
87
|
+
"FactCollector",
|
|
87
88
|
"FlirtAnalysis",
|
|
88
89
|
"ForwardAnalysis",
|
|
89
90
|
"Identifier",
|
|
@@ -9,7 +9,6 @@ import capstone
|
|
|
9
9
|
|
|
10
10
|
from pyvex.stmt import Put
|
|
11
11
|
from pyvex.expr import RdTmp
|
|
12
|
-
from archinfo.arch_arm import is_arm_arch, ArchARMHF
|
|
13
12
|
import ailment
|
|
14
13
|
|
|
15
14
|
from angr.code_location import ExternalCodeLocation
|
|
@@ -35,8 +34,9 @@ from angr.knowledge_plugins.variables.variable_access import VariableAccessSort
|
|
|
35
34
|
from angr.knowledge_plugins.functions import Function
|
|
36
35
|
from angr.utils.constants import DEFAULT_STATEMENT
|
|
37
36
|
from angr import SIM_PROCEDURES
|
|
38
|
-
from .
|
|
39
|
-
from . import
|
|
37
|
+
from angr.analyses import Analysis, register_analysis, ReachingDefinitionsAnalysis
|
|
38
|
+
from angr.analyses.reaching_definitions import get_all_definitions
|
|
39
|
+
from .utils import is_sane_register_variable
|
|
40
40
|
|
|
41
41
|
if TYPE_CHECKING:
|
|
42
42
|
from angr.knowledge_plugins.cfg import CFGModel
|
|
@@ -95,6 +95,8 @@ class CallingConventionAnalysis(Analysis):
|
|
|
95
95
|
callsite_block_addr: int | None = None,
|
|
96
96
|
callsite_insn_addr: int | None = None,
|
|
97
97
|
func_graph: networkx.DiGraph | None = None,
|
|
98
|
+
input_args: list[SimRegArg | SimStackArg] | None = None,
|
|
99
|
+
retval_size: int | None = None,
|
|
98
100
|
):
|
|
99
101
|
if func is not None and not isinstance(func, Function):
|
|
100
102
|
func = self.kb.functions[func]
|
|
@@ -106,6 +108,15 @@ class CallingConventionAnalysis(Analysis):
|
|
|
106
108
|
self.callsite_block_addr = callsite_block_addr
|
|
107
109
|
self.callsite_insn_addr = callsite_insn_addr
|
|
108
110
|
self._func_graph = func_graph
|
|
111
|
+
self._input_args = input_args
|
|
112
|
+
self._retval_size = retval_size
|
|
113
|
+
|
|
114
|
+
if self._retval_size is not None and self._input_args is None:
|
|
115
|
+
# retval size will be ignored if input_args is not specified - user error?
|
|
116
|
+
raise TypeError(
|
|
117
|
+
"input_args must be provided to use retval_size. Otherwise please set both input_args and "
|
|
118
|
+
"retval_size to None."
|
|
119
|
+
)
|
|
109
120
|
|
|
110
121
|
self.cc: SimCC | None = None
|
|
111
122
|
self.prototype: SimTypeFunction | None = None
|
|
@@ -308,9 +319,17 @@ class CallingConventionAnalysis(Analysis):
|
|
|
308
319
|
# we do not analyze SimProcedures or PLT stubs
|
|
309
320
|
return None
|
|
310
321
|
|
|
311
|
-
if
|
|
312
|
-
|
|
313
|
-
|
|
322
|
+
if self._input_args is None:
|
|
323
|
+
if not self._variable_manager.has_function_manager(self._function.addr):
|
|
324
|
+
l.warning("Please run variable recovery on %r before analyzing its calling convention.", self._function)
|
|
325
|
+
return None
|
|
326
|
+
vm = self._variable_manager[self._function.addr]
|
|
327
|
+
retval_size = vm.ret_val_size
|
|
328
|
+
input_variables = vm.input_variables()
|
|
329
|
+
input_args = self._args_from_vars(input_variables, vm)
|
|
330
|
+
else:
|
|
331
|
+
input_args = self._input_args
|
|
332
|
+
retval_size = self._retval_size
|
|
314
333
|
|
|
315
334
|
# check if this function is a variadic function
|
|
316
335
|
if self.project.arch.name == "AMD64":
|
|
@@ -319,11 +338,6 @@ class CallingConventionAnalysis(Analysis):
|
|
|
319
338
|
is_variadic = False
|
|
320
339
|
fixed_args = None
|
|
321
340
|
|
|
322
|
-
vm = self._variable_manager[self._function.addr]
|
|
323
|
-
|
|
324
|
-
input_variables = vm.input_variables()
|
|
325
|
-
input_args = self._args_from_vars(input_variables, vm)
|
|
326
|
-
|
|
327
341
|
# TODO: properly determine sp_delta
|
|
328
342
|
sp_delta = self.project.arch.bytes if self.project.arch.call_pushes_ret else 0
|
|
329
343
|
|
|
@@ -342,7 +356,7 @@ class CallingConventionAnalysis(Analysis):
|
|
|
342
356
|
args = args[:fixed_args]
|
|
343
357
|
|
|
344
358
|
# guess the type of the return value -- it's going to be a wild guess...
|
|
345
|
-
ret_type = self._guess_retval_type(cc,
|
|
359
|
+
ret_type = self._guess_retval_type(cc, retval_size)
|
|
346
360
|
if self._function.name == "main" and self.project.arch.bits == 64 and isinstance(ret_type, SimTypeLongLong):
|
|
347
361
|
# hack - main must return an int even in 64-bit binaries
|
|
348
362
|
ret_type = SimTypeInt()
|
|
@@ -698,14 +712,14 @@ class CallingConventionAnalysis(Analysis):
|
|
|
698
712
|
args.add(arg)
|
|
699
713
|
elif isinstance(variable, SimRegisterVariable):
|
|
700
714
|
# a register variable, convert it to a register argument
|
|
701
|
-
if not self.
|
|
715
|
+
if not is_sane_register_variable(self.project.arch, variable.reg, variable.size, def_cc=def_cc):
|
|
702
716
|
continue
|
|
703
|
-
reg_name = self.project.arch.translate_register_name(variable.reg, size=variable.size)
|
|
704
717
|
if self.project.arch.name in {"AMD64", "X86"} and variable.size < self.project.arch.bytes:
|
|
705
718
|
# use complete registers on AMD64 and X86
|
|
706
719
|
reg_name = self.project.arch.translate_register_name(variable.reg, size=self.project.arch.bytes)
|
|
707
720
|
arg = SimRegArg(reg_name, self.project.arch.bytes)
|
|
708
721
|
else:
|
|
722
|
+
reg_name = self.project.arch.translate_register_name(variable.reg, size=variable.size)
|
|
709
723
|
arg = SimRegArg(reg_name, variable.size)
|
|
710
724
|
args.add(arg)
|
|
711
725
|
|
|
@@ -748,53 +762,6 @@ class CallingConventionAnalysis(Analysis):
|
|
|
748
762
|
|
|
749
763
|
return args.difference(restored_reg_vars)
|
|
750
764
|
|
|
751
|
-
def _is_sane_register_variable(self, variable: SimRegisterVariable, def_cc: SimCC | None = None) -> bool:
|
|
752
|
-
"""
|
|
753
|
-
Filters all registers that are surly not members of function arguments.
|
|
754
|
-
This can be seen as a workaround, since VariableRecoveryFast sometimes gives input variables of cc_ndep (which
|
|
755
|
-
is a VEX-specific register) :-(
|
|
756
|
-
|
|
757
|
-
:param variable: The variable to test.
|
|
758
|
-
:return: True if it is an acceptable function argument, False otherwise.
|
|
759
|
-
:rtype: bool
|
|
760
|
-
"""
|
|
761
|
-
|
|
762
|
-
arch = self.project.arch
|
|
763
|
-
arch_name = arch.name
|
|
764
|
-
if ":" in arch_name:
|
|
765
|
-
# for pcode architectures, we only leave registers that are known to be used as input arguments
|
|
766
|
-
if def_cc is not None:
|
|
767
|
-
return arch.translate_register_name(variable.reg, size=variable.size) in def_cc.ARG_REGS
|
|
768
|
-
return True
|
|
769
|
-
|
|
770
|
-
# VEX
|
|
771
|
-
if arch_name == "AARCH64":
|
|
772
|
-
return 16 <= variable.reg < 80 # x0-x7
|
|
773
|
-
|
|
774
|
-
if arch_name == "AMD64":
|
|
775
|
-
return 24 <= variable.reg < 40 or 64 <= variable.reg < 104 # rcx, rdx # rsi, rdi, r8, r9, r10
|
|
776
|
-
# 224 <= variable.reg < 480) # xmm0-xmm7
|
|
777
|
-
|
|
778
|
-
if is_arm_arch(arch):
|
|
779
|
-
if isinstance(arch, ArchARMHF):
|
|
780
|
-
return 8 <= variable.reg < 24 or 128 <= variable.reg < 160 # r0 - 32 # s0 - s7, or d0 - d4
|
|
781
|
-
return 8 <= variable.reg < 24 # r0-r3
|
|
782
|
-
|
|
783
|
-
if arch_name == "MIPS32":
|
|
784
|
-
return 24 <= variable.reg < 40 # a0-a3
|
|
785
|
-
|
|
786
|
-
if arch_name == "MIPS64":
|
|
787
|
-
return 48 <= variable.reg < 80 or 112 <= variable.reg < 208 # a0-a3 or t4-t7
|
|
788
|
-
|
|
789
|
-
if arch_name == "PPC32":
|
|
790
|
-
return 28 <= variable.reg < 60 # r3-r10
|
|
791
|
-
|
|
792
|
-
if arch_name == "X86":
|
|
793
|
-
return 8 <= variable.reg < 24 or 160 <= variable.reg < 288 # eax, ebx, ecx, edx # xmm0-xmm7
|
|
794
|
-
|
|
795
|
-
l.critical("Unsupported architecture %s.", arch.name)
|
|
796
|
-
return True
|
|
797
|
-
|
|
798
765
|
def _reorder_args(self, args: list[SimRegArg | SimStackArg], cc: SimCC) -> list[SimRegArg | SimStackArg]:
|
|
799
766
|
"""
|
|
800
767
|
Reorder arguments according to the calling convention identified.
|
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import pyvex
|
|
5
|
+
import claripy
|
|
6
|
+
|
|
7
|
+
from angr.utils.bits import s2u, u2s
|
|
8
|
+
from angr.block import Block
|
|
9
|
+
from angr.analyses.analysis import Analysis
|
|
10
|
+
from angr.analyses import AnalysesHub
|
|
11
|
+
from angr.knowledge_plugins.functions import Function
|
|
12
|
+
from angr.codenode import BlockNode, HookNode
|
|
13
|
+
from angr.engines.light import SimEngineNostmtVEX, SimEngineLight, SpOffset, RegisterOffset
|
|
14
|
+
from angr.calling_conventions import SimRegArg, SimStackArg, default_cc
|
|
15
|
+
from angr.sim_type import SimTypeBottom
|
|
16
|
+
from .utils import is_sane_register_variable
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class FactCollectorState:
|
|
20
|
+
"""
|
|
21
|
+
The abstract state for FactCollector.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
__slots__ = (
|
|
25
|
+
"bp_value",
|
|
26
|
+
"callee_stored_regs",
|
|
27
|
+
"reg_reads",
|
|
28
|
+
"reg_writes",
|
|
29
|
+
"simple_stack",
|
|
30
|
+
"sp_value",
|
|
31
|
+
"stack_reads",
|
|
32
|
+
"stack_writes",
|
|
33
|
+
"tmps",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def __init__(self):
|
|
37
|
+
self.tmps = {}
|
|
38
|
+
self.simple_stack = {}
|
|
39
|
+
|
|
40
|
+
self.callee_stored_regs: dict[int, int] = {} # reg offset -> stack offset
|
|
41
|
+
self.reg_reads = {}
|
|
42
|
+
self.reg_writes: set[int] = set()
|
|
43
|
+
self.stack_reads = {}
|
|
44
|
+
self.stack_writes: set[int] = set()
|
|
45
|
+
self.sp_value = 0
|
|
46
|
+
self.bp_value = 0
|
|
47
|
+
|
|
48
|
+
def register_read(self, offset: int, size_in_bytes: int):
|
|
49
|
+
if offset in self.reg_writes:
|
|
50
|
+
return
|
|
51
|
+
if offset not in self.reg_reads:
|
|
52
|
+
self.reg_reads[offset] = size_in_bytes
|
|
53
|
+
else:
|
|
54
|
+
self.reg_reads[offset] = max(self.reg_reads[offset], size_in_bytes)
|
|
55
|
+
|
|
56
|
+
def register_written(self, offset: int, size_in_bytes: int):
|
|
57
|
+
for o in range(size_in_bytes):
|
|
58
|
+
self.reg_writes.add(offset + o)
|
|
59
|
+
|
|
60
|
+
def stack_read(self, offset: int, size_in_bytes: int):
|
|
61
|
+
if offset in self.stack_writes:
|
|
62
|
+
return
|
|
63
|
+
if offset not in self.stack_reads:
|
|
64
|
+
self.stack_reads[offset] = size_in_bytes
|
|
65
|
+
else:
|
|
66
|
+
self.stack_reads[offset] = max(self.stack_reads[offset], size_in_bytes)
|
|
67
|
+
|
|
68
|
+
def stack_written(self, offset: int, size_int_bytes: int):
|
|
69
|
+
for o in range(size_int_bytes):
|
|
70
|
+
self.stack_writes.add(offset + o)
|
|
71
|
+
|
|
72
|
+
def copy(self, with_tmps: bool = False) -> FactCollectorState:
|
|
73
|
+
new_state = FactCollectorState()
|
|
74
|
+
new_state.reg_reads = self.reg_reads.copy()
|
|
75
|
+
new_state.stack_reads = self.stack_reads.copy()
|
|
76
|
+
new_state.stack_writes = self.stack_writes.copy()
|
|
77
|
+
new_state.reg_writes = self.reg_writes.copy()
|
|
78
|
+
new_state.callee_stored_regs = self.callee_stored_regs.copy()
|
|
79
|
+
new_state.sp_value = self.sp_value
|
|
80
|
+
new_state.bp_value = self.bp_value
|
|
81
|
+
new_state.simple_stack = self.simple_stack.copy()
|
|
82
|
+
if with_tmps:
|
|
83
|
+
new_state.tmps = self.tmps.copy()
|
|
84
|
+
return new_state
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
binop_handler = SimEngineNostmtVEX[FactCollectorState, claripy.ast.BV, FactCollectorState].binop_handler
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class SimEngineFactCollectorVEX(
|
|
91
|
+
SimEngineNostmtVEX[FactCollectorState, SpOffset | RegisterOffset | int, None],
|
|
92
|
+
SimEngineLight[type[FactCollectorState], SpOffset | RegisterOffset | int, Block, None],
|
|
93
|
+
):
|
|
94
|
+
"""
|
|
95
|
+
THe engine for FactCollector.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
def __init__(self, project, bp_as_gpr: bool):
|
|
99
|
+
self.bp_as_gpr = bp_as_gpr
|
|
100
|
+
super().__init__(project)
|
|
101
|
+
|
|
102
|
+
def _process_block_end(self, stmt_result: list, whitelist: set[int] | None) -> None:
|
|
103
|
+
if self.block.vex.jumpkind == "Ijk_Call":
|
|
104
|
+
self.state.register_written(self.arch.ret_offset, self.arch.bytes)
|
|
105
|
+
|
|
106
|
+
def _top(self, bits: int):
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
def _is_top(self, expr: Any) -> bool:
|
|
110
|
+
raise NotImplementedError
|
|
111
|
+
|
|
112
|
+
def _handle_conversion(self, from_size: int, to_size: int, signed: bool, operand: pyvex.IRExpr) -> Any:
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
def _handle_stmt_Put(self, stmt):
|
|
116
|
+
v = self._expr(stmt.data)
|
|
117
|
+
if stmt.offset == self.arch.sp_offset and isinstance(v, SpOffset):
|
|
118
|
+
self.state.sp_value = v.offset
|
|
119
|
+
elif stmt.offset == self.arch.bp_offset and isinstance(v, SpOffset):
|
|
120
|
+
self.state.bp_value = v.offset
|
|
121
|
+
else:
|
|
122
|
+
self.state.register_written(stmt.offset, stmt.data.result_size(self.tyenv) // self.arch.byte_width)
|
|
123
|
+
|
|
124
|
+
def _handle_stmt_Store(self, stmt: pyvex.IRStmt.Store):
|
|
125
|
+
addr = self._expr(stmt.addr)
|
|
126
|
+
if isinstance(addr, SpOffset):
|
|
127
|
+
self.state.stack_written(addr.offset, stmt.data.result_size(self.tyenv) // self.arch.byte_width)
|
|
128
|
+
data = self._expr(stmt.data)
|
|
129
|
+
if isinstance(data, RegisterOffset) and not isinstance(data, SpOffset):
|
|
130
|
+
# push reg; we record the stored register as well as the stack slot offset
|
|
131
|
+
self.state.callee_stored_regs[data.reg] = u2s(addr.offset, self.arch.bits)
|
|
132
|
+
if isinstance(data, SpOffset):
|
|
133
|
+
self.state.simple_stack[addr.offset] = data
|
|
134
|
+
|
|
135
|
+
def _handle_stmt_WrTmp(self, stmt: pyvex.IRStmt.WrTmp):
|
|
136
|
+
v = self._expr(stmt.data)
|
|
137
|
+
if v is not None:
|
|
138
|
+
self.state.tmps[stmt.tmp] = v
|
|
139
|
+
|
|
140
|
+
def _handle_expr_Const(self, expr: pyvex.IRExpr.Const):
|
|
141
|
+
return expr.con.value
|
|
142
|
+
|
|
143
|
+
def _handle_expr_GSPTR(self, expr):
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
def _handle_expr_Get(self, expr) -> SpOffset | None:
|
|
147
|
+
if expr.offset == self.arch.sp_offset:
|
|
148
|
+
return SpOffset(self.arch.bits, self.state.sp_value, is_base=False)
|
|
149
|
+
if expr.offset == self.arch.bp_offset and not self.bp_as_gpr:
|
|
150
|
+
return SpOffset(self.arch.bits, self.state.bp_value, is_base=False)
|
|
151
|
+
bits = expr.result_size(self.tyenv)
|
|
152
|
+
self.state.register_read(expr.offset, bits // self.arch.byte_width)
|
|
153
|
+
return RegisterOffset(bits, expr.offset, 0)
|
|
154
|
+
|
|
155
|
+
def _handle_expr_GetI(self, expr):
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
def _handle_expr_ITE(self, expr):
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
def _handle_expr_Load(self, expr):
|
|
162
|
+
addr = self._expr(expr.addr)
|
|
163
|
+
if isinstance(addr, SpOffset):
|
|
164
|
+
self.state.stack_read(addr.offset, expr.result_size(self.tyenv) // self.arch.byte_width)
|
|
165
|
+
return self.state.simple_stack.get(addr.offset)
|
|
166
|
+
return None
|
|
167
|
+
|
|
168
|
+
def _handle_expr_RdTmp(self, expr):
|
|
169
|
+
return self.state.tmps.get(expr.tmp, None)
|
|
170
|
+
|
|
171
|
+
def _handle_expr_VECRET(self, expr):
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
@binop_handler
|
|
175
|
+
def _handle_binop_Add(self, expr):
|
|
176
|
+
op0, op1 = self._expr(expr.args[0]), self._expr(expr.args[1])
|
|
177
|
+
if isinstance(op0, SpOffset) and isinstance(op1, int):
|
|
178
|
+
return SpOffset(op0.bits, s2u(op0.offset + op1, op0.bits), is_base=op0.is_base)
|
|
179
|
+
if isinstance(op1, SpOffset) and isinstance(op0, int):
|
|
180
|
+
return SpOffset(op1.bits, s2u(op1.offset + op0, op1.bits), is_base=op1.is_base)
|
|
181
|
+
return None
|
|
182
|
+
|
|
183
|
+
@binop_handler
|
|
184
|
+
def _handle_binop_Sub(self, expr):
|
|
185
|
+
op0, op1 = self._expr(expr.args[0]), self._expr(expr.args[1])
|
|
186
|
+
if isinstance(op0, SpOffset) and isinstance(op1, int):
|
|
187
|
+
return SpOffset(op0.bits, s2u(op0.offset - op1, op0.bits), is_base=op0.is_base)
|
|
188
|
+
if isinstance(op1, SpOffset) and isinstance(op0, int):
|
|
189
|
+
return SpOffset(op1.bits, s2u(op1.offset - op0, op1.bits), is_base=op1.is_base)
|
|
190
|
+
return None
|
|
191
|
+
|
|
192
|
+
@binop_handler
|
|
193
|
+
def _handle_binop_And(self, expr):
|
|
194
|
+
op0, op1 = self._expr(expr.args[0]), self._expr(expr.args[1])
|
|
195
|
+
if isinstance(op0, SpOffset):
|
|
196
|
+
return op0
|
|
197
|
+
if isinstance(op1, SpOffset):
|
|
198
|
+
return op1
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class FactCollector(Analysis):
|
|
203
|
+
"""
|
|
204
|
+
An extremely fast analysis that extracts necessary facts of a function for CallingConventionAnalysis to make
|
|
205
|
+
decision on the calling convention and prototype of a function.
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
def __init__(self, func: Function, max_depth: int = 5):
|
|
209
|
+
self.function = func
|
|
210
|
+
self._max_depth = max_depth
|
|
211
|
+
|
|
212
|
+
self.input_args: list[SimRegArg | SimStackArg] | None = None
|
|
213
|
+
self.retval_size: int | None = None
|
|
214
|
+
|
|
215
|
+
self._analyze()
|
|
216
|
+
|
|
217
|
+
def _analyze(self):
|
|
218
|
+
# breadth-first search using function graph, collect registers and stack variables that are written to as well
|
|
219
|
+
# as read from, until max_depth is reached
|
|
220
|
+
|
|
221
|
+
end_states = self._analyze_startpoint()
|
|
222
|
+
self._analyze_endpoints_for_retval_size()
|
|
223
|
+
callee_restored_regs = self._analyze_endpoints_for_restored_regs()
|
|
224
|
+
self._determine_input_args(end_states, callee_restored_regs)
|
|
225
|
+
|
|
226
|
+
def _analyze_startpoint(self):
|
|
227
|
+
func_graph = self.function.transition_graph
|
|
228
|
+
startpoint = self.function.startpoint
|
|
229
|
+
bp_as_gpr = self.function.info.get("bp_as_gpr", False)
|
|
230
|
+
engine = SimEngineFactCollectorVEX(self.project, bp_as_gpr)
|
|
231
|
+
init_state = FactCollectorState()
|
|
232
|
+
if self.project.arch.call_pushes_ret:
|
|
233
|
+
init_state.sp_value = self.project.arch.bytes
|
|
234
|
+
init_state.bp_value = init_state.sp_value
|
|
235
|
+
|
|
236
|
+
traversed = set()
|
|
237
|
+
queue: list[tuple[int, FactCollectorState, BlockNode | HookNode | Function, BlockNode | HookNode | None]] = [
|
|
238
|
+
(0, init_state, startpoint, None)
|
|
239
|
+
]
|
|
240
|
+
end_states: list[FactCollectorState] = []
|
|
241
|
+
while queue:
|
|
242
|
+
depth, state, node, retnode = queue.pop(0)
|
|
243
|
+
traversed.add(node)
|
|
244
|
+
|
|
245
|
+
if depth > self._max_depth:
|
|
246
|
+
end_states.append(state)
|
|
247
|
+
break
|
|
248
|
+
|
|
249
|
+
if isinstance(node, BlockNode) and node.size == 0:
|
|
250
|
+
continue
|
|
251
|
+
if isinstance(node, HookNode):
|
|
252
|
+
# attempt to convert it into a function
|
|
253
|
+
if self.kb.functions.contains_addr(node.addr):
|
|
254
|
+
node = self.kb.functions.get_by_addr(node.addr)
|
|
255
|
+
else:
|
|
256
|
+
continue
|
|
257
|
+
if isinstance(node, Function):
|
|
258
|
+
if node.calling_convention is not None and node.prototype is not None:
|
|
259
|
+
# consume args and overwrite the return register
|
|
260
|
+
self._handle_function(state, node)
|
|
261
|
+
if node.returning is False or retnode is None:
|
|
262
|
+
# the function call does not return
|
|
263
|
+
end_states.append(state)
|
|
264
|
+
else:
|
|
265
|
+
# enqueue the retnode, but we don't increment the depth
|
|
266
|
+
new_state = state.copy()
|
|
267
|
+
if self.project.arch.call_pushes_ret:
|
|
268
|
+
new_state.sp_value += self.project.arch.bytes
|
|
269
|
+
queue.append((depth, new_state, retnode, None))
|
|
270
|
+
continue
|
|
271
|
+
|
|
272
|
+
block = self.project.factory.block(node.addr, size=node.size)
|
|
273
|
+
engine.process(state, block=block)
|
|
274
|
+
|
|
275
|
+
successor_added = False
|
|
276
|
+
call_succ, ret_succ = None, None
|
|
277
|
+
for _, succ, data in func_graph.out_edges(node, data=True):
|
|
278
|
+
edge_type = data.get("type")
|
|
279
|
+
if succ not in traversed and depth + 1 <= self._max_depth:
|
|
280
|
+
if edge_type == "fake_return":
|
|
281
|
+
ret_succ = succ
|
|
282
|
+
elif edge_type == "transition":
|
|
283
|
+
successor_added = True
|
|
284
|
+
queue.append((depth + 1, state.copy(), succ, None))
|
|
285
|
+
elif edge_type == "call":
|
|
286
|
+
call_succ = succ
|
|
287
|
+
if call_succ is not None:
|
|
288
|
+
successor_added = True
|
|
289
|
+
queue.append((depth + 1, state.copy(), call_succ, ret_succ))
|
|
290
|
+
|
|
291
|
+
if not successor_added:
|
|
292
|
+
end_states.append(state)
|
|
293
|
+
|
|
294
|
+
return end_states
|
|
295
|
+
|
|
296
|
+
def _handle_function(self, state: FactCollectorState, func: Function) -> None:
|
|
297
|
+
try:
|
|
298
|
+
arg_locs = func.calling_convention.arg_locs(func.prototype)
|
|
299
|
+
except (TypeError, ValueError):
|
|
300
|
+
func.prototype = None
|
|
301
|
+
return
|
|
302
|
+
|
|
303
|
+
if None in arg_locs:
|
|
304
|
+
return
|
|
305
|
+
|
|
306
|
+
for arg_loc in arg_locs:
|
|
307
|
+
for loc in arg_loc.get_footprint():
|
|
308
|
+
if isinstance(loc, SimRegArg):
|
|
309
|
+
state.register_read(self.project.arch.registers[loc.reg_name][0] + loc.reg_offset, loc.size)
|
|
310
|
+
elif isinstance(loc, SimStackArg):
|
|
311
|
+
sp_value = state.sp_value
|
|
312
|
+
if sp_value is not None:
|
|
313
|
+
state.stack_read(sp_value + loc.stack_offset, loc.size)
|
|
314
|
+
|
|
315
|
+
# clobber caller-saved regs
|
|
316
|
+
for reg_name in func.calling_convention.CALLER_SAVED_REGS:
|
|
317
|
+
offset = self.project.arch.registers[reg_name][0]
|
|
318
|
+
state.register_written(offset, self.project.arch.registers[reg_name][1])
|
|
319
|
+
|
|
320
|
+
def _analyze_endpoints_for_retval_size(self):
|
|
321
|
+
"""
|
|
322
|
+
Analyze all endpoints to determine the return value size.
|
|
323
|
+
"""
|
|
324
|
+
func_graph = self.function.transition_graph
|
|
325
|
+
cc_cls = default_cc(
|
|
326
|
+
self.project.arch.name, platform=self.project.simos.name if self.project.simos is not None else None
|
|
327
|
+
)
|
|
328
|
+
cc = cc_cls(self.project.arch)
|
|
329
|
+
if isinstance(cc.RETURN_VAL, SimRegArg):
|
|
330
|
+
retreg_offset = cc.RETURN_VAL.check_offset(self.project.arch)
|
|
331
|
+
else:
|
|
332
|
+
return
|
|
333
|
+
|
|
334
|
+
retval_sizes = []
|
|
335
|
+
for endpoint in self.function.endpoints:
|
|
336
|
+
traversed = set()
|
|
337
|
+
queue: list[tuple[int, BlockNode | HookNode]] = [(0, endpoint)]
|
|
338
|
+
while queue:
|
|
339
|
+
depth, node = queue.pop(0)
|
|
340
|
+
traversed.add(node)
|
|
341
|
+
|
|
342
|
+
if depth > 3:
|
|
343
|
+
break
|
|
344
|
+
|
|
345
|
+
if isinstance(node, BlockNode) and node.size == 0:
|
|
346
|
+
continue
|
|
347
|
+
if isinstance(node, HookNode):
|
|
348
|
+
# attempt to convert it into a function
|
|
349
|
+
if self.kb.functions.contains_addr(node.addr):
|
|
350
|
+
node = self.kb.functions.get_by_addr(node.addr)
|
|
351
|
+
else:
|
|
352
|
+
continue
|
|
353
|
+
if isinstance(node, Function):
|
|
354
|
+
if (
|
|
355
|
+
node.calling_convention is not None
|
|
356
|
+
and node.prototype is not None
|
|
357
|
+
and node.prototype.returnty is not None
|
|
358
|
+
and not isinstance(node.prototype.returnty, SimTypeBottom)
|
|
359
|
+
):
|
|
360
|
+
# assume the function overwrites the return variable
|
|
361
|
+
retval_size = (
|
|
362
|
+
node.prototype.returnty.with_arch(self.project.arch).size // self.project.arch.byte_width
|
|
363
|
+
)
|
|
364
|
+
retval_sizes.append(retval_size)
|
|
365
|
+
continue
|
|
366
|
+
|
|
367
|
+
block = self.project.factory.block(node.addr, size=node.size)
|
|
368
|
+
# scan the block statements backwards to find writes to the return value register
|
|
369
|
+
retval_size = None
|
|
370
|
+
for stmt in reversed(block.vex.statements):
|
|
371
|
+
if isinstance(stmt, pyvex.IRStmt.Put):
|
|
372
|
+
size = stmt.data.result_size(block.vex.tyenv) // self.project.arch.byte_width
|
|
373
|
+
if stmt.offset == retreg_offset:
|
|
374
|
+
retval_size = max(size, 1)
|
|
375
|
+
|
|
376
|
+
if retval_size is not None:
|
|
377
|
+
retval_sizes.append(retval_size)
|
|
378
|
+
continue
|
|
379
|
+
|
|
380
|
+
for pred, _, data in func_graph.in_edges(node, data=True):
|
|
381
|
+
edge_type = data.get("type")
|
|
382
|
+
if pred not in traversed and depth + 1 <= self._max_depth:
|
|
383
|
+
if edge_type == "fake_return":
|
|
384
|
+
continue
|
|
385
|
+
if edge_type in {"transition", "call"}:
|
|
386
|
+
queue.append((depth + 1, pred))
|
|
387
|
+
|
|
388
|
+
self.retval_size = max(retval_sizes) if retval_sizes else None
|
|
389
|
+
|
|
390
|
+
def _analyze_endpoints_for_restored_regs(self):
|
|
391
|
+
"""
|
|
392
|
+
Analyze all endpoints to determine the restored registers.
|
|
393
|
+
"""
|
|
394
|
+
func_graph = self.function.transition_graph
|
|
395
|
+
callee_restored_regs = set()
|
|
396
|
+
|
|
397
|
+
for endpoint in self.function.endpoints:
|
|
398
|
+
traversed = set()
|
|
399
|
+
queue: list[tuple[int, BlockNode | HookNode]] = [(0, endpoint)]
|
|
400
|
+
while queue:
|
|
401
|
+
depth, node = queue.pop(0)
|
|
402
|
+
traversed.add(node)
|
|
403
|
+
|
|
404
|
+
if depth > 3:
|
|
405
|
+
break
|
|
406
|
+
|
|
407
|
+
if isinstance(node, BlockNode) and node.size == 0:
|
|
408
|
+
continue
|
|
409
|
+
if isinstance(node, (HookNode, Function)):
|
|
410
|
+
continue
|
|
411
|
+
|
|
412
|
+
block = self.project.factory.block(node.addr, size=node.size)
|
|
413
|
+
# scan the block statements backwards to find all statements that restore registers from the stack
|
|
414
|
+
tmps = {}
|
|
415
|
+
for stmt in block.vex.statements:
|
|
416
|
+
if isinstance(stmt, pyvex.IRStmt.WrTmp):
|
|
417
|
+
if isinstance(stmt.data, pyvex.IRExpr.Get) and stmt.data.offset in {
|
|
418
|
+
self.project.arch.bp_offset,
|
|
419
|
+
self.project.arch.sp_offset,
|
|
420
|
+
}:
|
|
421
|
+
tmps[stmt.tmp] = "sp"
|
|
422
|
+
elif (
|
|
423
|
+
isinstance(stmt.data, pyvex.IRExpr.Load)
|
|
424
|
+
and isinstance(stmt.data.addr, pyvex.IRExpr.RdTmp)
|
|
425
|
+
and tmps.get(stmt.data.addr.tmp) == "sp"
|
|
426
|
+
):
|
|
427
|
+
tmps[stmt.tmp] = "stack_value"
|
|
428
|
+
elif isinstance(stmt.data, pyvex.IRExpr.Const):
|
|
429
|
+
tmps[stmt.tmp] = "const"
|
|
430
|
+
elif isinstance(stmt.data, pyvex.IRExpr.Binop) and ( # noqa:SIM102
|
|
431
|
+
stmt.data.op.startswith("Iop_Add") or stmt.data.op.startswith("Iop_Sub")
|
|
432
|
+
):
|
|
433
|
+
if (
|
|
434
|
+
isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp)
|
|
435
|
+
and tmps.get(stmt.data.args[0].tmp) == "sp"
|
|
436
|
+
) or (
|
|
437
|
+
isinstance(stmt.data.args[1], pyvex.IRExpr.RdTmp)
|
|
438
|
+
and tmps.get(stmt.data.args[1].tmp) == "sp"
|
|
439
|
+
):
|
|
440
|
+
tmps[stmt.tmp] = "sp"
|
|
441
|
+
if isinstance(stmt, pyvex.IRStmt.Put):
|
|
442
|
+
size = stmt.data.result_size(block.vex.tyenv) // self.project.arch.byte_width
|
|
443
|
+
# is the data loaded from the stack?
|
|
444
|
+
if (
|
|
445
|
+
size == self.project.arch.bytes
|
|
446
|
+
and isinstance(stmt.data, pyvex.IRExpr.RdTmp)
|
|
447
|
+
and tmps.get(stmt.data.tmp) == "stack_value"
|
|
448
|
+
):
|
|
449
|
+
callee_restored_regs.add(stmt.offset)
|
|
450
|
+
|
|
451
|
+
for pred, _, data in func_graph.in_edges(node, data=True):
|
|
452
|
+
edge_type = data.get("type")
|
|
453
|
+
if pred not in traversed and depth + 1 <= self._max_depth and edge_type == "transition":
|
|
454
|
+
queue.append((depth + 1, pred))
|
|
455
|
+
|
|
456
|
+
return callee_restored_regs
|
|
457
|
+
|
|
458
|
+
def _determine_input_args(self, end_states: list[FactCollectorState], callee_restored_regs: set[int]) -> None:
|
|
459
|
+
self.input_args = []
|
|
460
|
+
reg_offset_created = set()
|
|
461
|
+
callee_saved_regs = set()
|
|
462
|
+
callee_saved_reg_stack_offsets = set()
|
|
463
|
+
|
|
464
|
+
# determine callee-saved registers
|
|
465
|
+
for state in end_states:
|
|
466
|
+
for reg_offset, stack_offset in state.callee_stored_regs.items():
|
|
467
|
+
if reg_offset in callee_restored_regs:
|
|
468
|
+
callee_saved_regs.add(reg_offset)
|
|
469
|
+
callee_saved_reg_stack_offsets.add(stack_offset)
|
|
470
|
+
|
|
471
|
+
for state in end_states:
|
|
472
|
+
for offset, size in state.reg_reads.items():
|
|
473
|
+
if (
|
|
474
|
+
offset in reg_offset_created
|
|
475
|
+
or offset == self.project.arch.bp_offset
|
|
476
|
+
or not is_sane_register_variable(self.project.arch, offset, size)
|
|
477
|
+
or offset in callee_saved_regs
|
|
478
|
+
):
|
|
479
|
+
continue
|
|
480
|
+
reg_offset_created.add(offset)
|
|
481
|
+
if self.project.arch.name in {"AMD64", "X86"} and size < self.project.arch.bytes:
|
|
482
|
+
# use complete registers on AMD64 and X86
|
|
483
|
+
reg_name = self.project.arch.translate_register_name(offset, size=self.project.arch.bytes)
|
|
484
|
+
arg = SimRegArg(reg_name, self.project.arch.bytes)
|
|
485
|
+
else:
|
|
486
|
+
reg_name = self.project.arch.translate_register_name(offset, size=size)
|
|
487
|
+
arg = SimRegArg(reg_name, size)
|
|
488
|
+
self.input_args.append(arg)
|
|
489
|
+
|
|
490
|
+
stack_offset_created = set()
|
|
491
|
+
ret_addr_offset = 0 if not self.project.arch.call_pushes_ret else self.project.arch.bytes
|
|
492
|
+
for state in end_states:
|
|
493
|
+
for offset, size in state.stack_reads.items():
|
|
494
|
+
offset = u2s(offset, self.project.arch.bits)
|
|
495
|
+
if offset - ret_addr_offset > 0:
|
|
496
|
+
if offset in stack_offset_created or offset in callee_saved_reg_stack_offsets:
|
|
497
|
+
continue
|
|
498
|
+
stack_offset_created.add(offset)
|
|
499
|
+
arg = SimStackArg(offset - ret_addr_offset, size)
|
|
500
|
+
self.input_args.append(arg)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
AnalysesHub.register_default("FunctionFactCollector", FactCollector)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
import archinfo
|
|
5
|
+
from archinfo.arch_arm import is_arm_arch, ArchARMHF
|
|
6
|
+
|
|
7
|
+
from angr.calling_conventions import SimCC
|
|
8
|
+
|
|
9
|
+
l = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def is_sane_register_variable(arch: archinfo.Arch, reg_offset: int, reg_size: int, def_cc: SimCC | None = None) -> bool:
|
|
13
|
+
"""
|
|
14
|
+
Filters all registers that are surly not members of function arguments.
|
|
15
|
+
This can be seen as a workaround, since VariableRecoveryFast sometimes gives input variables of cc_ndep (which
|
|
16
|
+
is a VEX-specific register) :-(
|
|
17
|
+
|
|
18
|
+
:param reg_offset: The register offset.
|
|
19
|
+
:param reg_size: The register size.
|
|
20
|
+
:return: True if it is an acceptable function argument, False otherwise.
|
|
21
|
+
:rtype: bool
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
arch_name = arch.name
|
|
25
|
+
if ":" in arch_name:
|
|
26
|
+
# for pcode architectures, we only leave registers that are known to be used as input arguments
|
|
27
|
+
if def_cc is not None:
|
|
28
|
+
return arch.translate_register_name(reg_offset, size=reg_size) in def_cc.ARG_REGS
|
|
29
|
+
return True
|
|
30
|
+
|
|
31
|
+
# VEX
|
|
32
|
+
if arch_name == "AARCH64":
|
|
33
|
+
return 16 <= reg_offset < 80 # x0-x7
|
|
34
|
+
|
|
35
|
+
if arch_name == "AMD64":
|
|
36
|
+
return 24 <= reg_offset < 40 or 64 <= reg_offset < 104 # rcx, rdx # rsi, rdi, r8, r9, r10
|
|
37
|
+
# 224 <= reg_offset < 480) # xmm0-xmm7
|
|
38
|
+
|
|
39
|
+
if is_arm_arch(arch):
|
|
40
|
+
if isinstance(arch, ArchARMHF):
|
|
41
|
+
return 8 <= reg_offset < 24 or 128 <= reg_offset < 160 # r0 - 32 # s0 - s7, or d0 - d4
|
|
42
|
+
return 8 <= reg_offset < 24 # r0-r3
|
|
43
|
+
|
|
44
|
+
if arch_name == "MIPS32":
|
|
45
|
+
return 24 <= reg_offset < 40 # a0-a3
|
|
46
|
+
|
|
47
|
+
if arch_name == "MIPS64":
|
|
48
|
+
return 48 <= reg_offset < 80 or 112 <= reg_offset < 208 # a0-a3 or t4-t7
|
|
49
|
+
|
|
50
|
+
if arch_name == "PPC32":
|
|
51
|
+
return 28 <= reg_offset < 60 # r3-r10
|
|
52
|
+
|
|
53
|
+
if arch_name == "X86":
|
|
54
|
+
return 8 <= reg_offset < 24 or 160 <= reg_offset < 288 # eax, ebx, ecx, edx # xmm0-xmm7
|
|
55
|
+
|
|
56
|
+
l.critical("Unsupported architecture %s.", arch.name)
|
|
57
|
+
return True
|
|
@@ -7,6 +7,7 @@ import threading
|
|
|
7
7
|
import time
|
|
8
8
|
import logging
|
|
9
9
|
from collections import defaultdict
|
|
10
|
+
from enum import Enum
|
|
10
11
|
|
|
11
12
|
import networkx
|
|
12
13
|
|
|
@@ -16,7 +17,7 @@ from angr.utils.graph import GraphUtils
|
|
|
16
17
|
from angr.simos import SimWindows
|
|
17
18
|
from angr.utils.mp import mp_context, Initializer
|
|
18
19
|
from angr.knowledge_plugins.cfg import CFGModel
|
|
19
|
-
from . import Analysis, register_analysis, VariableRecoveryFast, CallingConventionAnalysis
|
|
20
|
+
from . import Analysis, register_analysis, VariableRecoveryFast, CallingConventionAnalysis, FactCollector
|
|
20
21
|
|
|
21
22
|
if TYPE_CHECKING:
|
|
22
23
|
from angr.calling_conventions import SimCC
|
|
@@ -30,6 +31,18 @@ _l = logging.getLogger(name=__name__)
|
|
|
30
31
|
_mp_context = mp_context()
|
|
31
32
|
|
|
32
33
|
|
|
34
|
+
class CallingConventionAnalysisMode(Enum):
|
|
35
|
+
"""
|
|
36
|
+
The mode of calling convention analysis.
|
|
37
|
+
|
|
38
|
+
FAST: Using FactCollector to collect facts, then use facts for calling convention analysis.
|
|
39
|
+
VARIABLES: Using variables in VariableManager for calling convention analysis.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
FAST = "fast"
|
|
43
|
+
VARIABLES = "variables"
|
|
44
|
+
|
|
45
|
+
|
|
33
46
|
class CompleteCallingConventionsAnalysis(Analysis):
|
|
34
47
|
"""
|
|
35
48
|
Implements full-binary calling convention analysis. During the initial analysis of a binary, you may set
|
|
@@ -39,6 +52,7 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
39
52
|
|
|
40
53
|
def __init__(
|
|
41
54
|
self,
|
|
55
|
+
mode: CallingConventionAnalysisMode = CallingConventionAnalysisMode.FAST,
|
|
42
56
|
recover_variables=False,
|
|
43
57
|
low_priority=False,
|
|
44
58
|
force=False,
|
|
@@ -71,6 +85,7 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
71
85
|
:param workers: Number of multiprocessing workers.
|
|
72
86
|
"""
|
|
73
87
|
|
|
88
|
+
self.mode = mode
|
|
74
89
|
self._recover_variables = recover_variables
|
|
75
90
|
self._low_priority = low_priority
|
|
76
91
|
self._force = force
|
|
@@ -88,6 +103,10 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
88
103
|
self._func_graphs = func_graphs if func_graphs else {}
|
|
89
104
|
self.prototype_libnames: set[str] = set()
|
|
90
105
|
|
|
106
|
+
# sanity check
|
|
107
|
+
if self.mode not in {CallingConventionAnalysisMode.FAST, CallingConventionAnalysisMode.VARIABLES}:
|
|
108
|
+
raise ValueError(f"Invalid calling convention analysis mode {self.mode}.")
|
|
109
|
+
|
|
91
110
|
self._func_addrs = [] # a list that holds addresses of all functions to be analyzed
|
|
92
111
|
self._results = []
|
|
93
112
|
if workers > 0:
|
|
@@ -322,7 +341,11 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
322
341
|
self.kb.variables.get_function_manager(func_addr),
|
|
323
342
|
)
|
|
324
343
|
|
|
325
|
-
if
|
|
344
|
+
if (
|
|
345
|
+
self.mode == CallingConventionAnalysisMode.VARIABLES
|
|
346
|
+
and self._recover_variables
|
|
347
|
+
and self.function_needs_variable_recovery(func)
|
|
348
|
+
):
|
|
326
349
|
# special case: we don't have a PCode-engine variable recovery analysis for PCode architectures!
|
|
327
350
|
if ":" in self.project.arch.name and self._func_graphs and func.addr in self._func_graphs:
|
|
328
351
|
# this is a pcode architecture
|
|
@@ -341,9 +364,15 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
341
364
|
)
|
|
342
365
|
return None, None, None, None
|
|
343
366
|
|
|
367
|
+
kwargs = {}
|
|
368
|
+
if self.mode == CallingConventionAnalysisMode.FAST:
|
|
369
|
+
facts = self.project.analyses[FactCollector].prep(kb=self.kb)(func)
|
|
370
|
+
kwargs["input_args"] = facts.input_args
|
|
371
|
+
kwargs["retval_size"] = facts.retval_size
|
|
372
|
+
|
|
344
373
|
# determine the calling convention of each function
|
|
345
374
|
cc_analysis = self.project.analyses[CallingConventionAnalysis].prep(kb=self.kb)(
|
|
346
|
-
func, cfg=self._cfg, analyze_callsites=self._analyze_callsites
|
|
375
|
+
func, cfg=self._cfg, analyze_callsites=self._analyze_callsites, **kwargs
|
|
347
376
|
)
|
|
348
377
|
|
|
349
378
|
if cc_analysis.cc is not None:
|
|
@@ -13,12 +13,6 @@ from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
|
13
13
|
_l = logging.getLogger(name=__name__)
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
def s2u(s, bits):
|
|
17
|
-
if s > 0:
|
|
18
|
-
return s
|
|
19
|
-
return (1 << bits) + s
|
|
20
|
-
|
|
21
|
-
|
|
22
16
|
class RegisterSaveAreaSimplifier(OptimizationPass):
|
|
23
17
|
"""
|
|
24
18
|
Optimizes away register spilling effects, including callee-saved registers.
|
|
@@ -5,18 +5,13 @@ import logging
|
|
|
5
5
|
|
|
6
6
|
import ailment
|
|
7
7
|
|
|
8
|
+
from angr.utils.bits import s2u
|
|
8
9
|
from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
_l = logging.getLogger(name=__name__)
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
def s2u(s, bits):
|
|
15
|
-
if s > 0:
|
|
16
|
-
return s
|
|
17
|
-
return (1 << bits) + s
|
|
18
|
-
|
|
19
|
-
|
|
20
15
|
class StackCanarySimplifier(OptimizationPass):
|
|
21
16
|
"""
|
|
22
17
|
Removes stack canary checks from decompilation results.
|
|
@@ -17,12 +17,6 @@ from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
|
17
17
|
_l = logging.getLogger(name=__name__)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
def s2u(s, bits):
|
|
21
|
-
if s > 0:
|
|
22
|
-
return s
|
|
23
|
-
return (1 << bits) + s
|
|
24
|
-
|
|
25
|
-
|
|
26
20
|
class SwitchDefaultCaseDuplicator(OptimizationPass):
|
|
27
21
|
"""
|
|
28
22
|
For each switch-case construct (identified by jump tables), duplicate the default-case node when we detect
|
|
@@ -13,12 +13,6 @@ from .optimization_pass import OptimizationPass, OptimizationPassStage
|
|
|
13
13
|
_l = logging.getLogger(name=__name__)
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
def s2u(s, bits):
|
|
17
|
-
if s > 0:
|
|
18
|
-
return s
|
|
19
|
-
return (1 << bits) + s
|
|
20
|
-
|
|
21
|
-
|
|
22
16
|
class WinStackCanarySimplifier(OptimizationPass):
|
|
23
17
|
"""
|
|
24
18
|
Removes stack canary checks from decompilation results for Windows PE files.
|
|
@@ -215,6 +215,11 @@ class SimEngineVRVEX(
|
|
|
215
215
|
addr = RichR(loc.stack_offset + one_sp)
|
|
216
216
|
self._load(addr, loc.size)
|
|
217
217
|
|
|
218
|
+
# clobber caller-saved registers
|
|
219
|
+
for reg_name in func.calling_convention.CALLER_SAVED_REGS:
|
|
220
|
+
reg_offset, reg_size = self.arch.registers[reg_name]
|
|
221
|
+
self._assign_to_register(reg_offset, self._top(reg_size * self.arch.byte_width), reg_size)
|
|
222
|
+
|
|
218
223
|
def _process_block_end(self, stmt_result, whitelist):
|
|
219
224
|
# handles block-end calls
|
|
220
225
|
current_addr = self.state.block_addr
|
angr/calling_conventions.py
CHANGED
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
from typing import cast
|
|
5
5
|
from collections.abc import Iterable
|
|
6
6
|
from collections import defaultdict
|
|
7
|
+
import contextlib
|
|
7
8
|
|
|
8
9
|
import claripy
|
|
9
10
|
import archinfo
|
|
@@ -33,7 +34,6 @@ from .sim_type import (
|
|
|
33
34
|
)
|
|
34
35
|
from .state_plugins.sim_action_object import SimActionObject
|
|
35
36
|
from .engines.soot.engine import SootMixin
|
|
36
|
-
import contextlib
|
|
37
37
|
|
|
38
38
|
l = logging.getLogger(name=__name__)
|
|
39
39
|
l.addFilter(UniqueLogFilter())
|
|
@@ -656,7 +656,7 @@ class SimCC:
|
|
|
656
656
|
self.next_arg(session, SimTypePointer(SimTypeBottom()))
|
|
657
657
|
return session
|
|
658
658
|
|
|
659
|
-
def return_in_implicit_outparam(self, ty):
|
|
659
|
+
def return_in_implicit_outparam(self, ty): # pylint:disable=unused-argument
|
|
660
660
|
return False
|
|
661
661
|
|
|
662
662
|
def stack_space(self, args):
|
|
@@ -1098,7 +1098,8 @@ class SimCC:
|
|
|
1098
1098
|
all_fp_args: set[int | str] = {_arg_ident(a) for a in sample_inst.fp_args}
|
|
1099
1099
|
all_int_args: set[int | str] = {_arg_ident(a) for a in sample_inst.int_args}
|
|
1100
1100
|
both_iter = sample_inst.memory_args
|
|
1101
|
-
|
|
1101
|
+
max_args = cls._guess_arg_count(args)
|
|
1102
|
+
some_both_args: set[int | str] = {_arg_ident(next(both_iter)) for _ in range(max_args)}
|
|
1102
1103
|
|
|
1103
1104
|
new_args = []
|
|
1104
1105
|
for arg in args:
|
|
@@ -1115,6 +1116,13 @@ class SimCC:
|
|
|
1115
1116
|
|
|
1116
1117
|
return True
|
|
1117
1118
|
|
|
1119
|
+
@classmethod
|
|
1120
|
+
def _guess_arg_count(cls, args, limit: int = 64) -> int:
|
|
1121
|
+
# pylint:disable=not-callable
|
|
1122
|
+
stack_args = [a for a in args if isinstance(a, SimStackArg)]
|
|
1123
|
+
stack_arg_count = (max(a.stack_offset for a in stack_args) // cls.ARCH().bytes + 1) if stack_args else 0
|
|
1124
|
+
return min(limit, max(len(args), stack_arg_count))
|
|
1125
|
+
|
|
1118
1126
|
@staticmethod
|
|
1119
1127
|
def find_cc(
|
|
1120
1128
|
arch: archinfo.Arch, args: list[SimFunctionArgument], sp_delta: int, platform: str = "Linux"
|
|
@@ -1687,7 +1695,7 @@ class SimCCARM(SimCC):
|
|
|
1687
1695
|
raise NotImplementedError("Bug. Report to @rhelmot")
|
|
1688
1696
|
elif cls == "MEMORY":
|
|
1689
1697
|
mapped_classes.append(next(session.both_iter))
|
|
1690
|
-
elif cls
|
|
1698
|
+
elif cls in {"INTEGER", "SINGLEP"}:
|
|
1691
1699
|
try:
|
|
1692
1700
|
mapped_classes.append(next(session.int_iter))
|
|
1693
1701
|
except StopIteration:
|
|
@@ -12,7 +12,6 @@ from cle.backends.symbol import Symbol
|
|
|
12
12
|
from archinfo.arch_arm import get_real_address_if_arm
|
|
13
13
|
import claripy
|
|
14
14
|
|
|
15
|
-
from angr.block import Block
|
|
16
15
|
from angr.knowledge_plugins.cfg.memory_data import MemoryDataSort
|
|
17
16
|
|
|
18
17
|
from angr.codenode import CodeNode, BlockNode, HookNode, SyscallNode
|
|
@@ -403,7 +402,7 @@ class Function(Serializable):
|
|
|
403
402
|
def nodes(self) -> Iterable[CodeNode]:
|
|
404
403
|
return self.transition_graph.nodes()
|
|
405
404
|
|
|
406
|
-
def get_node(self, addr) ->
|
|
405
|
+
def get_node(self, addr) -> BlockNode | None:
|
|
407
406
|
return self._addr_to_block_node.get(addr, None)
|
|
408
407
|
|
|
409
408
|
@property
|
|
@@ -1036,8 +1035,9 @@ class Function(Serializable):
|
|
|
1036
1035
|
if function.returning is False:
|
|
1037
1036
|
# the target function does not return
|
|
1038
1037
|
the_node = self.get_node(src.addr)
|
|
1039
|
-
|
|
1040
|
-
|
|
1038
|
+
if the_node is not None:
|
|
1039
|
+
self._callout_sites.add(the_node)
|
|
1040
|
+
self._add_endpoint(the_node, "call")
|
|
1041
1041
|
|
|
1042
1042
|
def get_call_sites(self) -> Iterable[int]:
|
|
1043
1043
|
"""
|
|
@@ -460,6 +460,12 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
|
|
|
460
460
|
:rtype: Function or None
|
|
461
461
|
"""
|
|
462
462
|
if name is not None and name.startswith("sub_"):
|
|
463
|
+
# first check if a function with the specified name exists
|
|
464
|
+
for func in self.get_by_name(name, check_previous_names=check_previous_names):
|
|
465
|
+
if plt is None or func.is_plt == plt:
|
|
466
|
+
return func
|
|
467
|
+
|
|
468
|
+
# then enter the syntactic sugar mode
|
|
463
469
|
try:
|
|
464
470
|
addr = int(name.split("_")[-1], 16)
|
|
465
471
|
name = None
|
angr/lib/angr_native.dylib
CHANGED
|
Binary file
|
angr/utils/bits.py
CHANGED
|
@@ -31,3 +31,16 @@ def zeroextend_on_demand(op0: claripy.ast.BV, op1: claripy.ast.BV) -> claripy.as
|
|
|
31
31
|
if op0.size() > op1.size():
|
|
32
32
|
return claripy.ZeroExt(op0.size() - op1.size(), op1)
|
|
33
33
|
return op1
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def s2u(s, bits):
|
|
37
|
+
mask = (1 << bits) - 1
|
|
38
|
+
if s > 0:
|
|
39
|
+
return s & mask
|
|
40
|
+
return ((1 << bits) + s) & mask
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def u2s(u, bits):
|
|
44
|
+
if u < (1 << (bits - 1)):
|
|
45
|
+
return u
|
|
46
|
+
return (u & ((1 << bits) - 1)) - (1 << bits)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: angr
|
|
3
|
-
Version: 9.2.
|
|
3
|
+
Version: 9.2.135
|
|
4
4
|
Summary: A multi-architecture binary analysis toolkit, with the ability to perform dynamic symbolic execution and various static analyses on binaries
|
|
5
5
|
Home-page: https://github.com/angr/angr
|
|
6
6
|
License: BSD-2-Clause
|
|
@@ -16,13 +16,13 @@ Description-Content-Type: text/markdown
|
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: CppHeaderParser
|
|
18
18
|
Requires-Dist: GitPython
|
|
19
|
-
Requires-Dist: ailment==9.2.
|
|
20
|
-
Requires-Dist: archinfo==9.2.
|
|
19
|
+
Requires-Dist: ailment==9.2.135
|
|
20
|
+
Requires-Dist: archinfo==9.2.135
|
|
21
21
|
Requires-Dist: cachetools
|
|
22
22
|
Requires-Dist: capstone==5.0.3
|
|
23
23
|
Requires-Dist: cffi>=1.14.0
|
|
24
|
-
Requires-Dist: claripy==9.2.
|
|
25
|
-
Requires-Dist: cle==9.2.
|
|
24
|
+
Requires-Dist: claripy==9.2.135
|
|
25
|
+
Requires-Dist: cle==9.2.135
|
|
26
26
|
Requires-Dist: itanium-demangler
|
|
27
27
|
Requires-Dist: mulpyplexer
|
|
28
28
|
Requires-Dist: nampa
|
|
@@ -31,7 +31,7 @@ Requires-Dist: protobuf>=5.28.2
|
|
|
31
31
|
Requires-Dist: psutil
|
|
32
32
|
Requires-Dist: pycparser>=2.18
|
|
33
33
|
Requires-Dist: pyformlang
|
|
34
|
-
Requires-Dist: pyvex==9.2.
|
|
34
|
+
Requires-Dist: pyvex==9.2.135
|
|
35
35
|
Requires-Dist: rich>=13.1.0
|
|
36
36
|
Requires-Dist: sortedcontainers
|
|
37
37
|
Requires-Dist: sympy
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
angr/__init__.py,sha256=
|
|
1
|
+
angr/__init__.py,sha256=odyiYDh0AXyqpY0ivUXjx-rMAeY96FK0_h_7pMp_sFU,9153
|
|
2
2
|
angr/__main__.py,sha256=XeawhF6Cco9eWcfMTDWzYYggLB3qjnQ87IIeFOplaHM,2873
|
|
3
3
|
angr/annocfg.py,sha256=0NIvcuCskwz45hbBzigUTAuCrYutjDMwEXtMJf0y0S0,10742
|
|
4
4
|
angr/blade.py,sha256=NhesOPloKJC1DQJRv_HBT18X7oNxK16JwAfNz2Lc1o0,15384
|
|
5
5
|
angr/block.py,sha256=4mP-OKNqiTxOf2-GPfyKokpuF4j4ua_o5WZcC7W6BL8,14815
|
|
6
6
|
angr/callable.py,sha256=1rzhXjWlx62jKJaRKHvp12rbsJ75zNa86vXtCt6eFLo,6065
|
|
7
|
-
angr/calling_conventions.py,sha256=
|
|
7
|
+
angr/calling_conventions.py,sha256=zciZ1DAct9heBs-2CkVpkvT2yK5jExIom3SoA9WW2ug,93409
|
|
8
8
|
angr/code_location.py,sha256=kXNJDEMge9VRHadrK4E6HQ8wDdCaHSXNqyAZuHDEGuM,5397
|
|
9
9
|
angr/codenode.py,sha256=hehAHvUuxgUYiVtCFMTxloYC6bO4_CQjcp_52WWDHMA,3781
|
|
10
10
|
angr/errors.py,sha256=I0L-TbxmVYIkC-USuHwaQ9BGPi2YVObnhZXQQ3kJFuo,8385
|
|
@@ -26,19 +26,18 @@ angr/slicer.py,sha256=DND0BERanYKafasRH9MDFAng0rSjdjmzXj2-phCD6CQ,10634
|
|
|
26
26
|
angr/state_hierarchy.py,sha256=qDQCUGXmQm3vOxE3CSoiqTH4OAFFOWZZt9BLhNpeOhA,8484
|
|
27
27
|
angr/tablespecs.py,sha256=Kx1e87FxTx3_ZN7cAHWZSRpdInT4Vfj5gExAWtLkLTw,3259
|
|
28
28
|
angr/vaults.py,sha256=v_RBKEGN2wkyOoskC_akKSlawcRtMicukKh1O1hxrJk,9719
|
|
29
|
-
angr/analyses/__init__.py,sha256=
|
|
29
|
+
angr/analyses/__init__.py,sha256=JVCNQfvffUjtvz5kvzvtYKmH_yG1Qjy-caSuQ8JMgpw,3470
|
|
30
30
|
angr/analyses/analysis.py,sha256=7Jkob2CBEXHzW7F1hZk9AqfOKLglpfHplpyxba1fN_4,14998
|
|
31
31
|
angr/analyses/backward_slice.py,sha256=a9uro3rqqDDiQRCnDCQzaSRcZvDQkCdRzLsrx5xe8uM,27219
|
|
32
32
|
angr/analyses/binary_optimizer.py,sha256=Sm05TR-F5QtU1qx9jKr2lGfj03xw_O1IyBJjwnoUjJ0,26160
|
|
33
33
|
angr/analyses/bindiff.py,sha256=AGOlH6Hsofo-6WwEleX80-DYs70aV-P8JV-GiDnoT9A,51391
|
|
34
34
|
angr/analyses/boyscout.py,sha256=pMJNmVBt8MbCiVe8Pk8SQ3IOppHGK2qHe6G7A3e3WA8,2483
|
|
35
35
|
angr/analyses/callee_cleanup_finder.py,sha256=aogcfYfvzsVPVfseJl2KKczMu7pPPtwC7bqTyQ0UsvI,2812
|
|
36
|
-
angr/analyses/calling_convention.py,sha256=tW8NgKRCN9wjc5YpkzBV8hckAAoRKrb0EXjl3kBVa70,40869
|
|
37
36
|
angr/analyses/cdg.py,sha256=oPgHV4MVpGkfRUE0ZiaghBSkgTsr6tkG1IK4f_GtOBA,6230
|
|
38
37
|
angr/analyses/class_identifier.py,sha256=bytFQ0c7KuQhbYPPJDkhtV0ZU_Xo8_9KLZxHe9TtyMs,3010
|
|
39
38
|
angr/analyses/code_tagging.py,sha256=Gj7Ms24RnmhC9OD57gw7R6_c-pLfqSug-LVUMw_JmXE,3510
|
|
40
39
|
angr/analyses/codecave.py,sha256=k_dDhMN4wcq2bs5VrwpOv96OowQ7AbZSs6j5Z6YbIpk,2209
|
|
41
|
-
angr/analyses/complete_calling_conventions.py,sha256=
|
|
40
|
+
angr/analyses/complete_calling_conventions.py,sha256=Jsl9YgYW4OaRFBXqcXNTt_AwKoHMP2M7NIMh3kZYodI,19356
|
|
42
41
|
angr/analyses/congruency_check.py,sha256=SRlUKJaylCQydWsb4AGG8LUGuh5RwI8ksKZL6jf-4P8,16166
|
|
43
42
|
angr/analyses/datagraph_meta.py,sha256=Ng0jqLD5ucRn_fBXhYq3l6scs3kczRk6Sk-Sen1forc,3414
|
|
44
43
|
angr/analyses/ddg.py,sha256=c8P8zCkem7P717PYIJD35evK64Oh8YBa_tj6LdCeuTQ,63229
|
|
@@ -65,6 +64,10 @@ angr/analyses/vfg.py,sha256=_RDuP83ts55-FTVNMQGx7MJD1aDvNw4FHDhCwa7nUFw,72879
|
|
|
65
64
|
angr/analyses/vsa_ddg.py,sha256=NQUauuMPZVrW7oCPpvIl-OIvGWUZHk_xEVLw3SCYzj8,16137
|
|
66
65
|
angr/analyses/vtable.py,sha256=1Ed7jzr99rk9VgOGzcxBw_6GFqby5mIdSTGPqQPhcZM,3872
|
|
67
66
|
angr/analyses/xrefs.py,sha256=vs6cpVmwXHOmxrI9lJUwCRMYbPSqvIQXS5_fINMaOGI,10290
|
|
67
|
+
angr/analyses/calling_convention/__init__.py,sha256=bK5VS6AxT5l86LAhTL7l1HUT9IuvXG9x9ikbIohIFoE,194
|
|
68
|
+
angr/analyses/calling_convention/calling_convention.py,sha256=_fTXe9oVCJ61roZrWhRRv_5FGtiQpiJmlLkf1x3ZL9Q,39692
|
|
69
|
+
angr/analyses/calling_convention/fact_collector.py,sha256=FCRGdAr6VmROUemKM3ibpJ4LU3rUT3PwC312zkq6sT4,21334
|
|
70
|
+
angr/analyses/calling_convention/utils.py,sha256=A4m85U1gd_dEuPEjlh4vWBC-mxxozOFIGIhApmgTvdI,2017
|
|
68
71
|
angr/analyses/cfg/__init__.py,sha256=-w8Vd6FD6rtjlQaQ7MxwmliFgS2zt-kZepAY4gHas04,446
|
|
69
72
|
angr/analyses/cfg/cfb.py,sha256=2Iej5PhB_U9JbfvvBuXy_07_UY9j7yiztKZYrGnc0U0,15369
|
|
70
73
|
angr/analyses/cfg/cfg.py,sha256=ZHZFWtP4uD1YxgKy44O_oD_BiSo871Llcd1zpXmFkBE,3177
|
|
@@ -154,17 +157,17 @@ angr/analyses/decompiler/optimization_passes/ite_region_converter.py,sha256=gsWg
|
|
|
154
157
|
angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py,sha256=ldEBDJTwS-FfzIkvCilCDY8IxzarHTXxv4jNZG28XDU,38818
|
|
155
158
|
angr/analyses/decompiler/optimization_passes/mod_simplifier.py,sha256=BzgSGM39Uv1WAGPM831wLnKW8t-mw9tQoV07ZlxbU_Y,3379
|
|
156
159
|
angr/analyses/decompiler/optimization_passes/optimization_pass.py,sha256=EYls4BcE4z1Hjvhez5oodKWLjLZe_KpRgKQZV0hck3Q,22637
|
|
157
|
-
angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py,sha256=
|
|
160
|
+
angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py,sha256=X6A252YhqUvT7A6J5NqCKBom2PRlh5NDHpAjXfNvBfg,7854
|
|
158
161
|
angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py,sha256=GIFiYM_C_ChHrD2D1JGRFlE--PU3FOxTqzOX-lXmJLY,6404
|
|
159
162
|
angr/analyses/decompiler/optimization_passes/ret_deduplicator.py,sha256=STMnRyZWiqdoGPa3c7Q4KCHv-JHUdJ2t4oLEltEMpII,7995
|
|
160
163
|
angr/analyses/decompiler/optimization_passes/return_duplicator_base.py,sha256=7QO_sJBR8WgjRxD8PXwxu0NeoCQchNJNClcwMzEmOsU,24921
|
|
161
164
|
angr/analyses/decompiler/optimization_passes/return_duplicator_high.py,sha256=ICDYwQJt5E2OVasdqn42jzbjwUXhSj6Plh3Y1iUHpAQ,2178
|
|
162
165
|
angr/analyses/decompiler/optimization_passes/return_duplicator_low.py,sha256=-mBEVfwGz986lDDEGwBG8wvGQTrFZHE7TLV-7rWt-H0,10076
|
|
163
|
-
angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py,sha256=
|
|
164
|
-
angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py,sha256=
|
|
166
|
+
angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py,sha256=vHfTCTG33r-PwwikP8tBbNqWvNt-SvRZfOsDNeAdiPc,14421
|
|
167
|
+
angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py,sha256=gvGpjP3t-an8iIBkmPGXob0-aRHL2idGZpd7hErlgFo,6461
|
|
165
168
|
angr/analyses/decompiler/optimization_passes/switch_reused_entry_rewriter.py,sha256=m7ZMkqE2qbl4rl4M_Fi8xS6I1vUaTzUBIzsE6qpbwkM,4020
|
|
166
169
|
angr/analyses/decompiler/optimization_passes/tag_slicer.py,sha256=8_gmoeYgDD1Hb8Rpqcb-01_B4897peDF-J6KA5PjQT8,1176
|
|
167
|
-
angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py,sha256=
|
|
170
|
+
angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py,sha256=57AlQgCbaPSiY7OwcKdOXnr0LUACCO0r1TweqIDyUzo,12728
|
|
168
171
|
angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py,sha256=6NxaX2oT6BMkevb8xt9vlS3Jl-CmSK59F0FVab68B48,3088
|
|
169
172
|
angr/analyses/decompiler/optimization_passes/duplication_reverter/__init__.py,sha256=hTeOdooVDZnBnjiAguD7_BS9YJru8rOiSHN3H0sdzcA,126
|
|
170
173
|
angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py,sha256=nLu-s4wn6b3z6MlItwCH1kWpeAc4C-fP3MNN3WRCSuo,21666
|
|
@@ -351,7 +354,7 @@ angr/analyses/variable_recovery/__init__.py,sha256=eA1SHzfSx8aPufUdkvgMmBnbI6VDY
|
|
|
351
354
|
angr/analyses/variable_recovery/annotations.py,sha256=2va7cXnRHYqVqXeVt00QanxfAo3zanL4BkAcC0-Bk20,1438
|
|
352
355
|
angr/analyses/variable_recovery/engine_ail.py,sha256=ZmJCMH_y0oYdLRTwHw34MOy-5_9SgrklLgnLLLtHf5k,31197
|
|
353
356
|
angr/analyses/variable_recovery/engine_base.py,sha256=ZqIlYpEPSB5WmhQ6p8H0HIMkRUG7ISMlCDOsHuE4-Sc,51146
|
|
354
|
-
angr/analyses/variable_recovery/engine_vex.py,sha256=
|
|
357
|
+
angr/analyses/variable_recovery/engine_vex.py,sha256=UAA2FpOq4lAjsBzy5FoIOoR9dF4615UFNLDlDiWEfCs,20645
|
|
355
358
|
angr/analyses/variable_recovery/irsb_scanner.py,sha256=vWplxRc-iwIJsQ5aHWH1t29zdyLPjfklm8h3CWHseng,5143
|
|
356
359
|
angr/analyses/variable_recovery/variable_recovery.py,sha256=s5hwY9oOibhLxsJIePhYRmrX0mrDIi_zKkfNblwYyhE,22169
|
|
357
360
|
angr/analyses/variable_recovery/variable_recovery_base.py,sha256=cJsc64ev_UmWTb2KNTdRF3HtpZyh4J2CEgnUAlH2MVg,15181
|
|
@@ -518,8 +521,8 @@ angr/knowledge_plugins/cfg/cfg_node.py,sha256=mAvQ8XAEURM7y0suc_S9lfxCmfXSTJHmWB
|
|
|
518
521
|
angr/knowledge_plugins/cfg/indirect_jump.py,sha256=W3KWpH7Sx-6Z7h_BwQjCK_XfP3ce_MaeAu_Aaq3D3qg,2072
|
|
519
522
|
angr/knowledge_plugins/cfg/memory_data.py,sha256=QLxFZfrtwz8u6UJn1L-Sxa-C8S0Gy9IOlfNfHCLPIow,5056
|
|
520
523
|
angr/knowledge_plugins/functions/__init__.py,sha256=asiLNiT6sHbjP6eU-kDpawIoVxv4J35cwz5yQHtQ2E0,167
|
|
521
|
-
angr/knowledge_plugins/functions/function.py,sha256=
|
|
522
|
-
angr/knowledge_plugins/functions/function_manager.py,sha256=
|
|
524
|
+
angr/knowledge_plugins/functions/function.py,sha256=Kiyi18e8ex8OpoQmbX4MHoHyZOGNLeAP3t-SvERiDtU,67326
|
|
525
|
+
angr/knowledge_plugins/functions/function_manager.py,sha256=cU_0alc7yQ_AE5pm2NiCicjAaeL6zLX4KntQAqy32Ws,19893
|
|
523
526
|
angr/knowledge_plugins/functions/function_parser.py,sha256=cpxn0EYp8qTqVQUBfwxodNIEFuNojdQboJG-q7uLdd0,11822
|
|
524
527
|
angr/knowledge_plugins/functions/soot_function.py,sha256=kAEzniVHa2FOjb2qlLElXtbbgAeeUkor7iQIFyJuoYY,5005
|
|
525
528
|
angr/knowledge_plugins/key_definitions/__init__.py,sha256=-x1VGH3LHMze3T-RygodvUG3oXXa5jhKvjXoPKyiU_0,432
|
|
@@ -548,7 +551,7 @@ angr/knowledge_plugins/xrefs/__init__.py,sha256=5PhqVOtTZ27lCjJ9wp7akUeJydqILbyC
|
|
|
548
551
|
angr/knowledge_plugins/xrefs/xref.py,sha256=U2H1rfffp5EXoh0awlGxMBxA4K5MIwl3CXjV3Uih3tA,4856
|
|
549
552
|
angr/knowledge_plugins/xrefs/xref_manager.py,sha256=Yb88z3L8Y26TfGeRHdsGWQlT9f6oWntjEg6s-kcVtUQ,4040
|
|
550
553
|
angr/knowledge_plugins/xrefs/xref_types.py,sha256=LcQ9pD4E4XlC51Us49xiqAoGAFGpnCrpYO4mOzILiKI,308
|
|
551
|
-
angr/lib/angr_native.dylib,sha256=
|
|
554
|
+
angr/lib/angr_native.dylib,sha256=38Yl0HzTM7bzS8x6DRHepTjDyK9rmOw716DiAUhEhM4,18820608
|
|
552
555
|
angr/misc/__init__.py,sha256=FoUwjk1DhqlIsr2sBN0MlR8MnSOGQv9QJhxmq32RYuA,355
|
|
553
556
|
angr/misc/ansi.py,sha256=nPJHC0SKfqasMQZ0LxdmmIYojjmk4nr5jI6FrzoTwS0,811
|
|
554
557
|
angr/misc/autoimport.py,sha256=iZagpuPwZWczUTYIqs-JkDMQjftMqc_cchcm7OBFiEg,3450
|
|
@@ -1333,7 +1336,7 @@ angr/storage/memory_mixins/regioned_memory/static_find_mixin.py,sha256=tWyiNrMxm
|
|
|
1333
1336
|
angr/utils/__init__.py,sha256=kBUIJCp9WSgzb62zMg4puUUeheMSl9U4RFqkfiL3en8,1159
|
|
1334
1337
|
angr/utils/ail.py,sha256=8_FloZ6cP89D2Nfc_2wCPcuVv7ny-aP-OKS3syCSMLk,1054
|
|
1335
1338
|
angr/utils/algo.py,sha256=4TaEFE4tU-59KyRVFASqXeoiwH01ZMj5fZd_JVcpdOY,1038
|
|
1336
|
-
angr/utils/bits.py,sha256=
|
|
1339
|
+
angr/utils/bits.py,sha256=_eWPyymSbj01jsLexicRtD_X7sUKKj_fTUI0DEIZ-rc,1054
|
|
1337
1340
|
angr/utils/constants.py,sha256=ZnK6Ed-1U_8yaw-7ZaCLSM0-z7bSuKPg715bBrquxKE,257
|
|
1338
1341
|
angr/utils/cowdict.py,sha256=qx2iO1rrCDTQUGX9dqi9ZAly2Dgm6bCEgdSAQw9MxRM,2159
|
|
1339
1342
|
angr/utils/dynamic_dictlist.py,sha256=bHQrxhUCkk6NDDzEBouAWESjMyKfQUJIk8g38R27iXw,3048
|
|
@@ -1354,9 +1357,9 @@ angr/utils/timing.py,sha256=ELuRPzdRSHzOATgtAzTFByMlVr021ypMrsvtpopreLg,1481
|
|
|
1354
1357
|
angr/utils/ssa/__init__.py,sha256=OD3eTWAiH9QXGpwliNBCTC3Z4bux9iBX3Sp50aUNHvI,8758
|
|
1355
1358
|
angr/utils/ssa/tmp_uses_collector.py,sha256=rSpvMxBHzg-tmvhsfjn3iLyPEKzaZN-xpQrdslMq3J4,793
|
|
1356
1359
|
angr/utils/ssa/vvar_uses_collector.py,sha256=8gfAWdRMz73Deh-ZshDM3GPAot9Lf-rHzCiaCil0hlE,1342
|
|
1357
|
-
angr-9.2.
|
|
1358
|
-
angr-9.2.
|
|
1359
|
-
angr-9.2.
|
|
1360
|
-
angr-9.2.
|
|
1361
|
-
angr-9.2.
|
|
1362
|
-
angr-9.2.
|
|
1360
|
+
angr-9.2.135.dist-info/LICENSE,sha256=cgL_ho5B1NH8UxwtBuqThRWdjear8b7hktycaS1sz6g,1327
|
|
1361
|
+
angr-9.2.135.dist-info/METADATA,sha256=Ls0VQIZqogjAt1EPMIvz_70vDMvP4J1vNj2eNH6nT-4,4762
|
|
1362
|
+
angr-9.2.135.dist-info/WHEEL,sha256=dYIPLwxtxe-ENqXjLxewAHnumMwYQtssgKNOBq_TWGc,106
|
|
1363
|
+
angr-9.2.135.dist-info/entry_points.txt,sha256=Vjh1C8PMyr5dZFMnik5WkEP01Uwr2T73I3a6N32sgQU,44
|
|
1364
|
+
angr-9.2.135.dist-info/top_level.txt,sha256=dKw0KWTbwLXytFvv15oAAG4sUs3ey47tt6DorJG9-hw,5
|
|
1365
|
+
angr-9.2.135.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|