angr 9.2.134__py3-none-manylinux2014_aarch64.whl → 9.2.135__py3-none-manylinux2014_aarch64.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 CHANGED
@@ -2,7 +2,7 @@
2
2
  # pylint: disable=wrong-import-position
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "9.2.134"
5
+ __version__ = "9.2.135"
6
6
 
7
7
  if bytes is str:
8
8
  raise Exception(
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",
@@ -0,0 +1,6 @@
1
+ from __future__ import annotations
2
+ from .calling_convention import CallingConventionAnalysis
3
+ from .fact_collector import FactCollector
4
+
5
+
6
+ __all__ = ["CallingConventionAnalysis", "FactCollector"]
@@ -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 .reaching_definitions import get_all_definitions
39
- from . import Analysis, register_analysis, ReachingDefinitionsAnalysis
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 not self._variable_manager.has_function_manager(self._function.addr):
312
- l.warning("Please run variable recovery on %r before analyzing its calling convention.", self._function)
313
- return None
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, vm.ret_val_size)
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._is_sane_register_variable(variable, def_cc=def_cc):
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 self._recover_variables and self.function_needs_variable_recovery(func):
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
@@ -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
- some_both_args: set[int | str] = {_arg_ident(next(both_iter)) for _ in range(len(args))}
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 == "INTEGER" or cls == "SINGLEP":
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) -> Block:
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
- self._callout_sites.add(the_node)
1040
- self._add_endpoint(the_node, "call")
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/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.134
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.134
20
- Requires-Dist: archinfo==9.2.134
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.134
25
- Requires-Dist: cle==9.2.134
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.134
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=RdEZBtno9mn8PRTf_VSkaLK0AnqKMT1zIMQkRyqJAfI,9153
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=TZZXPPAOFYqoKfq6KYpItgpf-FInNzfit13meSb4TTg,92979
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=Tj98rg_BM_YBK7EIYrvfcyIxQnMnzFrMZp4-Id43rFE,3434
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=rwsVfq0TUOx-YW2RtbeXajAreBEfs9QDyQAE51PnEfo,18279
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=tc4FruEl0sFpm1DUu9g8gWlueRm0t9rhfHsdUrVplBo,7932
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=Fviff-U5n3_9kHWsbMbW0_FRQhK_010nhuq83Pg8gOU,14467
164
- angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py,sha256=nMI9geZiLG5diaI3YciNKvJ0PAZXtUBLgAfknCf48QE,6539
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=cpbsP6_ilZDu2M_jX8TEnwVrsQXljHEjSMw25HyK6PM,12806
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=2xb7zlNrD3PpNILlDUvTp9Vt9JdhOqn3O3zIe101-QQ,20368
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=6G479_dWkp0PAAEKQWCUY3pH0b-qcOWjT9O6dOt4NLk,67287
522
- angr/knowledge_plugins/functions/function_manager.py,sha256=R-VtbkN3-l1-U4Wk4XHC8lGZo7DpXbEDE7Ok986YYYI,19594
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
@@ -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=flNgPQ_OlAxk-SsW2lv_DbLSkqYc7J4jGd8VRB_WJE8,817
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.134.dist-info/LICENSE,sha256=cgL_ho5B1NH8UxwtBuqThRWdjear8b7hktycaS1sz6g,1327
1358
- angr-9.2.134.dist-info/METADATA,sha256=F82cwrJZ-zYDIYDpEL9zylN0aNkwmUle6tmDKM2kffg,4762
1359
- angr-9.2.134.dist-info/WHEEL,sha256=-NJbNRco0VfEz3luq7ku84EsJsWGgW5ZrO0zAtrzmbo,109
1360
- angr-9.2.134.dist-info/entry_points.txt,sha256=Vjh1C8PMyr5dZFMnik5WkEP01Uwr2T73I3a6N32sgQU,44
1361
- angr-9.2.134.dist-info/top_level.txt,sha256=dKw0KWTbwLXytFvv15oAAG4sUs3ey47tt6DorJG9-hw,5
1362
- angr-9.2.134.dist-info/RECORD,,
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=-NJbNRco0VfEz3luq7ku84EsJsWGgW5ZrO0zAtrzmbo,109
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