angr 9.2.172__cp310-abi3-macosx_10_12_x86_64.whl → 9.2.173__cp310-abi3-macosx_10_12_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 CHANGED
@@ -2,7 +2,7 @@
2
2
  # pylint: disable=wrong-import-position
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "9.2.172"
5
+ __version__ = "9.2.173"
6
6
 
7
7
  if bytes is str:
8
8
  raise Exception(
@@ -622,10 +622,15 @@ class FactCollector(Analysis):
622
622
 
623
623
  stack_offset_created = set()
624
624
  ret_addr_offset = 0 if not self.project.arch.call_pushes_ret else self.project.arch.bytes
625
+ # handle shadow stack args
626
+ cc_cls = default_cc(
627
+ self.project.arch.name, platform=self.project.simos.name if self.project.simos is not None else None
628
+ )
629
+ stackarg_sp_buff = cc_cls.STACKARG_SP_BUFF if cc_cls is not None else 0
625
630
  for state in end_states:
626
631
  for offset, size in state.stack_reads.items():
627
632
  offset = u2s(offset, self.project.arch.bits)
628
- if offset - ret_addr_offset > 0:
633
+ if offset - ret_addr_offset > stackarg_sp_buff:
629
634
  if offset in stack_offset_created or offset in callee_saved_reg_stack_offsets:
630
635
  continue
631
636
  stack_offset_created.add(offset)
@@ -3237,22 +3237,24 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
3237
3237
  # Fill in the jump_tables dict
3238
3238
  self.jump_tables[jump.addr] = jump
3239
3239
  # occupy the jump table region
3240
- if jump.jumptable_addr is not None:
3241
- self._seg_list.occupy(jump.jumptable_addr, jump.jumptable_size, "data")
3240
+ for jumptable_info in jump.jumptables:
3241
+ if jumptable_info.addr is None:
3242
+ continue
3243
+ self._seg_list.occupy(jumptable_info.addr, jumptable_info.size, "data")
3242
3244
  if self._collect_data_ref:
3243
- if jump.jumptable_addr in self._memory_data:
3244
- memory_data = self._memory_data[jump.jumptable_addr]
3245
- memory_data.size = jump.jumptable_size
3246
- memory_data.max_size = jump.jumptable_size
3245
+ if jumptable_info.addr in self._memory_data:
3246
+ memory_data = self._memory_data[jumptable_info.addr]
3247
+ memory_data.size = jumptable_info.size
3248
+ memory_data.max_size = jumptable_info.size
3247
3249
  memory_data.sort = MemoryDataSort.Unknown
3248
3250
  else:
3249
3251
  memory_data = MemoryData(
3250
- jump.jumptable_addr,
3251
- jump.jumptable_size,
3252
+ jumptable_info.addr,
3253
+ jumptable_info.size,
3252
3254
  MemoryDataSort.Unknown,
3253
- max_size=jump.jumptable_size,
3255
+ max_size=jumptable_info.size,
3254
3256
  )
3255
- self._memory_data[jump.jumptable_addr] = memory_data
3257
+ self._memory_data[jumptable_info.addr] = memory_data
3256
3258
 
3257
3259
  jump.resolved_targets = targets
3258
3260
  all_targets = set(targets)
@@ -780,7 +780,7 @@ class JumpTableResolver(IndirectJumpResolver):
780
780
  self._find_bss_region()
781
781
 
782
782
  def filter(self, cfg, addr, func_addr, block, jumpkind):
783
- if pcode is not None and isinstance(block.vex, pcode.lifter.IRSB):
783
+ if pcode is not None and isinstance(block.vex, pcode.lifter.IRSB): # type:ignore
784
784
  if once("pcode__indirect_jump_resolver"):
785
785
  l.warning("JumpTableResolver does not support P-Code IR yet; CFG may be incomplete.")
786
786
  return False
@@ -1049,6 +1049,7 @@ class JumpTableResolver(IndirectJumpResolver):
1049
1049
 
1050
1050
  # Get the jumping targets
1051
1051
  for r in simgr.found:
1052
+ jt2, jt2_addr, jt2_entrysize, jt2_size = None, None, None, None
1052
1053
  if load_stmt is not None:
1053
1054
  ret = self._try_resolve_targets_load(
1054
1055
  r,
@@ -1064,7 +1065,18 @@ class JumpTableResolver(IndirectJumpResolver):
1064
1065
  if ret is None:
1065
1066
  # Try the next state
1066
1067
  continue
1067
- jump_table, jumptable_addr, entry_size, jumptable_size, all_targets, sort = ret
1068
+ (
1069
+ jump_table,
1070
+ jumptable_addr,
1071
+ entry_size,
1072
+ jumptable_size,
1073
+ all_targets,
1074
+ sort,
1075
+ jt2,
1076
+ jt2_addr,
1077
+ jt2_entrysize,
1078
+ jt2_size,
1079
+ ) = ret
1068
1080
  if sort == "jumptable":
1069
1081
  ij_type = IndirectJumpType.Jumptable_AddressLoadedFromMemory
1070
1082
  elif sort == "vtable":
@@ -1116,15 +1128,14 @@ class JumpTableResolver(IndirectJumpResolver):
1116
1128
  ij.jumptable = True
1117
1129
  else:
1118
1130
  ij.jumptable = False
1119
- ij.jumptable_addr = jumptable_addr
1120
- ij.jumptable_size = jumptable_size
1121
- ij.jumptable_entry_size = entry_size
1131
+ ij.add_jumptable(jumptable_addr, jumptable_size, entry_size, jump_table, is_primary=True)
1122
1132
  ij.resolved_targets = set(jump_table)
1123
- ij.jumptable_entries = jump_table
1124
1133
  ij.type = ij_type
1125
1134
  else:
1126
1135
  ij.jumptable = False
1127
1136
  ij.resolved_targets = set(jump_table)
1137
+ if jt2 is not None and jt2_addr is not None and jt2_size is not None and jt2_entrysize is not None:
1138
+ ij.add_jumptable(jt2_addr, jt2_size, jt2_entrysize, jt2, is_primary=False)
1128
1139
 
1129
1140
  return True, all_targets
1130
1141
 
@@ -1560,7 +1571,9 @@ class JumpTableResolver(IndirectJumpResolver):
1560
1571
  stmt_whitelist = annotatedcfg.get_whitelisted_statements(block_addr)
1561
1572
  assert isinstance(stmt_whitelist, list)
1562
1573
  try:
1563
- engine.process(state, block=block, whitelist=stmt_whitelist)
1574
+ engine.process(
1575
+ state, block=block, whitelist=set(stmt_whitelist) if stmt_whitelist is not None else None
1576
+ )
1564
1577
  except (claripy.ClaripyError, SimError, AngrError):
1565
1578
  # anything can happen
1566
1579
  break
@@ -1789,7 +1802,18 @@ class JumpTableResolver(IndirectJumpResolver):
1789
1802
  )
1790
1803
  else:
1791
1804
  l.debug("Table at %#x has %d plausible targets", table_base_addr, num_targets)
1792
- return jump_table, table_base_addr, load_size, num_targets * load_size, jump_table, sort
1805
+ return (
1806
+ jump_table,
1807
+ table_base_addr,
1808
+ load_size,
1809
+ num_targets * load_size,
1810
+ jump_table,
1811
+ sort,
1812
+ None,
1813
+ None,
1814
+ None,
1815
+ None,
1816
+ )
1793
1817
 
1794
1818
  # We resolved too many targets for this indirect jump. Something might have gone wrong.
1795
1819
  l.debug(
@@ -1848,6 +1872,7 @@ class JumpTableResolver(IndirectJumpResolver):
1848
1872
  # Adjust entries inside the jump table
1849
1873
  mask = (2**self.project.arch.bits) - 1
1850
1874
  transformation_list = list(reversed([v for v in transformations.values() if not v.first_load]))
1875
+ jt_2nd_memloads: dict[int, int] = {}
1851
1876
  if transformation_list:
1852
1877
 
1853
1878
  def handle_signed_ext(a):
@@ -1872,6 +1897,10 @@ class JumpTableResolver(IndirectJumpResolver):
1872
1897
  return (a + con) & mask
1873
1898
 
1874
1899
  def handle_load(size, a):
1900
+ if a not in jt_2nd_memloads:
1901
+ jt_2nd_memloads[a] = size
1902
+ else:
1903
+ jt_2nd_memloads[a] = max(jt_2nd_memloads[a], size)
1875
1904
  return cfg._fast_memory_load_pointer(a, size=size)
1876
1905
 
1877
1906
  invert_conversion_ops = []
@@ -1936,6 +1965,31 @@ class JumpTableResolver(IndirectJumpResolver):
1936
1965
  l.debug("Could not recover jump table")
1937
1966
  return None
1938
1967
 
1968
+ # there might be a secondary jumptable
1969
+ jt_2nd = self._get_secondary_jumptable_from_transformations(transformation_list)
1970
+ jt_2nd_entries: list[int] | None = None
1971
+ jt_2nd_baseaddr: int | None = None
1972
+ jt_2nd_entrysize: int | None = None
1973
+ jt_2nd_size: int | None = None
1974
+ if jt_2nd is not None and jt_2nd_memloads:
1975
+ # determine the size of the secondary jump table
1976
+ jt_2nd_baseaddr, jt_2nd_entrysize = jt_2nd
1977
+ if jt_2nd_baseaddr in jt_2nd_memloads:
1978
+ jt_2nd_size = max(jt_2nd_memloads) - jt_2nd_baseaddr + jt_2nd_entrysize
1979
+ if jt_2nd_size % jt_2nd_entrysize == 0:
1980
+ jt_2nd_entrycount = jt_2nd_size // jt_2nd_entrysize
1981
+ if jt_2nd_entrycount <= len(all_targets):
1982
+ # we found it!
1983
+ jt_2nd_entries = []
1984
+ for i in range(jt_2nd_entrycount):
1985
+ target = cfg._fast_memory_load_pointer(
1986
+ jt_2nd_baseaddr + i * jt_2nd_entrysize,
1987
+ size=jt_2nd_entrysize,
1988
+ )
1989
+ if target is None:
1990
+ break
1991
+ jt_2nd_entries.append(target)
1992
+
1939
1993
  # Finally... all targets are ready
1940
1994
  illegal_target_found = False
1941
1995
  for target in all_targets:
@@ -1953,7 +2007,18 @@ class JumpTableResolver(IndirectJumpResolver):
1953
2007
  if illegal_target_found:
1954
2008
  return None
1955
2009
 
1956
- return jump_table, min_jumptable_addr, load_size, total_cases * load_size, all_targets, sort
2010
+ return (
2011
+ jump_table,
2012
+ min_jumptable_addr,
2013
+ load_size,
2014
+ total_cases * load_size,
2015
+ all_targets,
2016
+ sort,
2017
+ jt_2nd_entries,
2018
+ jt_2nd_baseaddr,
2019
+ jt_2nd_entrysize,
2020
+ jt_2nd_size,
2021
+ )
1957
2022
 
1958
2023
  def _try_resolve_targets_ite(
1959
2024
  self, r, addr, cfg, annotatedcfg, ite_stmt: pyvex.IRStmt.WrTmp
@@ -2279,6 +2344,64 @@ class JumpTableResolver(IndirectJumpResolver):
2279
2344
  return None
2280
2345
  return jump_addr
2281
2346
 
2347
+ def _get_secondary_jumptable_from_transformations(
2348
+ self, transformations: list[AddressTransformation]
2349
+ ) -> tuple[int, int] | None:
2350
+ """
2351
+ Find the potential secondary "jump table" from a list of transformations.
2352
+
2353
+ :param transformations: A list of address transformations.
2354
+ :return: A tuple of [jump_table_addr, entry_size] if a secondary jump table is found. None otherwise.
2355
+ """
2356
+
2357
+ # find all add-(add-)load sequence
2358
+
2359
+ for i in range(len(transformations) - 1):
2360
+ prev_tran = transformations[i - 1] if i - 1 >= 0 else None
2361
+ tran = transformations[i]
2362
+ if not (
2363
+ tran.op == AddressTransformationTypes.Add
2364
+ and (prev_tran is None or prev_tran.op != AddressTransformationTypes.Add)
2365
+ ):
2366
+ continue
2367
+ next_tran = transformations[i + 1]
2368
+ add_tran, load_tran = None, None
2369
+ if next_tran.op == AddressTransformationTypes.Load:
2370
+ add_tran = None
2371
+ load_tran = next_tran
2372
+ elif next_tran.op == AddressTransformationTypes.Add:
2373
+ next2_tran = transformations[i + 2] if i + 2 < len(transformations) else None
2374
+ if next2_tran is not None and next2_tran.op == AddressTransformationTypes.Load:
2375
+ add_tran = next_tran
2376
+ load_tran = next2_tran
2377
+
2378
+ if load_tran is None:
2379
+ continue
2380
+ # we have found an add-(add-)load sequence
2381
+ jumptable_base_addr = None
2382
+ if isinstance(tran.operands[0], AddressOperand) and isinstance(tran.operands[1], int):
2383
+ jumptable_base_addr = tran.operands[1]
2384
+ elif isinstance(tran.operands[1], AddressOperand) and isinstance(tran.operands[0], int):
2385
+ jumptable_base_addr = tran.operands[0]
2386
+ else:
2387
+ # unsupported first add
2388
+ continue
2389
+
2390
+ if add_tran is not None:
2391
+ mask = (1 << self.project.arch.bits) - 1
2392
+ if isinstance(add_tran.operands[0], AddressOperand) and isinstance(add_tran.operands[1], int):
2393
+ jumptable_base_addr = (jumptable_base_addr + add_tran.operands[1]) & mask
2394
+ elif isinstance(add_tran.operands[1], AddressOperand) and isinstance(add_tran.operands[0], int):
2395
+ jumptable_base_addr = (jumptable_base_addr + add_tran.operands[0]) & mask
2396
+ else:
2397
+ # unsupported second add
2398
+ continue
2399
+
2400
+ load_size = load_tran.operands[1]
2401
+ # we have a potential secondary jump table!
2402
+ return jumptable_base_addr, load_size
2403
+ return None
2404
+
2282
2405
  def _sp_moved_up(self, block) -> bool:
2283
2406
  """
2284
2407
  Examine if the stack pointer moves up (if any values are popped out of the stack) within a single block.
@@ -303,6 +303,23 @@ class BlockSimplifier(Analysis):
303
303
  return block.copy(statements=new_statements)
304
304
 
305
305
  def _eliminate_dead_assignments(self, block):
306
+
307
+ def _statement_has_calls(stmt: Statement) -> bool:
308
+ """
309
+ Check if a statement has any Call expressions.
310
+ """
311
+ walker = HasCallExprWalker()
312
+ walker.walk_statement(stmt)
313
+ return walker.has_call_expr
314
+
315
+ def _expression_has_calls(expr: Expression) -> bool:
316
+ """
317
+ Check if an expression has any Call expressions.
318
+ """
319
+ walker = HasCallExprWalker()
320
+ walker.walk_expression(expr)
321
+ return walker.has_call_expr
322
+
306
323
  new_statements = []
307
324
  if not block.statements:
308
325
  return block
@@ -325,8 +342,11 @@ class BlockSimplifier(Analysis):
325
342
  # micro optimization: if all statements that use a tmp are going to be removed, we remove this tmp as well
326
343
  for tmp, used_locs in rd.all_tmp_uses[block_loc].items():
327
344
  used_at = {stmt_idx for _, stmt_idx in used_locs}
328
- if used_at.issubset(dead_defs_stmt_idx):
329
- continue
345
+ if used_at.issubset(dead_defs_stmt_idx): # noqa:SIM102
346
+ # cannot remove this tmp if any use sites involve call expressions; this is basically a duplicate of
347
+ # the logic in the larger loop below
348
+ if all(not _statement_has_calls(block.statements[i]) for i in used_at):
349
+ continue
330
350
  used_tmps.add(tmp.tmp_idx)
331
351
 
332
352
  # Remove dead assignments
@@ -337,9 +357,7 @@ class BlockSimplifier(Analysis):
337
357
  # is it assigning to an unused tmp or a dead virgin?
338
358
 
339
359
  # does .src involve any Call expressions? if so, we cannot remove it
340
- walker = HasCallExprWalker()
341
- walker.walk_expression(stmt.src)
342
- if not walker.has_call_expr:
360
+ if not _expression_has_calls(stmt.src):
343
361
  continue
344
362
 
345
363
  if type(stmt.dst) is Tmp and isinstance(stmt.src, Call):
@@ -2158,10 +2158,9 @@ class Clinic(Analysis):
2158
2158
  # custom string?
2159
2159
  if hasattr(expr, "custom_string") and expr.custom_string is True:
2160
2160
  s = self.kb.custom_strings[expr.value]
2161
+ ty = expr.type if hasattr(expr, "type") else SimTypePointer(SimTypeChar()).with_arch(self.project.arch)
2161
2162
  expr.tags["reference_values"] = {
2162
- SimTypePointer(SimTypeChar().with_arch(self.project.arch)).with_arch(self.project.arch): s.decode(
2163
- "latin-1"
2164
- ),
2163
+ ty: s,
2165
2164
  }
2166
2165
  else:
2167
2166
  # global variable?
@@ -47,6 +47,7 @@ from .inlined_memcpy import InlinedMemcpy
47
47
  from .inlined_strcpy import InlinedStrcpy
48
48
  from .inlined_strcpy_consolidation import InlinedStrcpyConsolidation
49
49
  from .inlined_wstrcpy import InlinedWstrcpy
50
+ from .inlined_wstrcpy_consolidation import InlinedWstrcpyConsolidation
50
51
  from .cmpord_rewriter import CmpORDRewriter
51
52
  from .coalesce_adjacent_shrs import CoalesceAdjacentShiftRights
52
53
  from .a_mul_const_sub_a import AMulConstSubA
@@ -104,6 +105,7 @@ ALL_PEEPHOLE_OPTS: list[type[PeepholeOptimizationExprBase]] = [
104
105
  InlinedStrcpy,
105
106
  InlinedStrcpyConsolidation,
106
107
  InlinedWstrcpy,
108
+ InlinedWstrcpyConsolidation,
107
109
  CmpORDRewriter,
108
110
  CoalesceAdjacentShiftRights,
109
111
  ShlToMul,
@@ -1,7 +1,7 @@
1
1
  # pylint:disable=arguments-differ,too-many-boolean-expressions
2
2
  from __future__ import annotations
3
3
 
4
- from angr.ailment.expression import BinaryOp, Load
4
+ from angr.ailment.expression import BinaryOp, Load, Expression, Tmp
5
5
  from angr.ailment.statement import CAS, ConditionalJump, Statement, Assignment, Call
6
6
 
7
7
  from .base import PeepholeOptimizationMultiStmtBase
@@ -60,11 +60,13 @@ class CASIntrinsics(PeepholeOptimizationMultiStmtBase):
60
60
  and next_stmt.ins_addr == cas_stmt.ins_addr
61
61
  ):
62
62
  addr = cas_stmt.addr
63
+ expd_lo = self._resolve_tmp_expr(cas_stmt.expd_lo, block)
64
+ next_stmt_cond_op1 = self._resolve_tmp_expr(next_stmt.condition.operands[1], block)
63
65
  if (
64
- isinstance(cas_stmt.expd_lo, Load)
65
- and cas_stmt.expd_lo.addr.likes(addr)
66
- and isinstance(next_stmt.condition.operands[1], Load)
67
- and next_stmt.condition.operands[1].addr.likes(addr)
66
+ isinstance(expd_lo, Load)
67
+ and expd_lo.addr.likes(addr)
68
+ and isinstance(next_stmt_cond_op1, Load)
69
+ and next_stmt_cond_op1.addr.likes(addr)
68
70
  and cas_stmt.old_lo.likes(next_stmt.condition.operands[0])
69
71
  and cas_stmt.old_hi is None
70
72
  ):
@@ -113,3 +115,11 @@ class CASIntrinsics(PeepholeOptimizationMultiStmtBase):
113
115
  os = "Linux"
114
116
  return _INTRINSICS_NAMES[mnemonic][os]
115
117
  return mnemonic
118
+
119
+ @staticmethod
120
+ def _resolve_tmp_expr(expr: Expression, block) -> Expression:
121
+ if isinstance(expr, Tmp):
122
+ for stmt in block.statements:
123
+ if isinstance(stmt, Assignment) and stmt.dst.likes(expr):
124
+ return stmt.src
125
+ return expr
@@ -4,15 +4,17 @@ import string
4
4
 
5
5
  from archinfo import Endness
6
6
 
7
+ from angr.ailment import BinaryOp
7
8
  from angr.ailment.expression import Const, StackBaseOffset, VirtualVariable
8
- from angr.ailment.statement import Call, Assignment
9
+ from angr.ailment.statement import Call, Assignment, Statement, Store
9
10
 
11
+ from angr.sim_type import SimTypePointer, SimTypeWideChar
10
12
  from angr.utils.endness import ail_const_to_be
11
13
  from .base import PeepholeOptimizationStmtBase
12
14
 
13
15
 
14
- ASCII_PRINTABLES = set(string.printable)
15
- ASCII_DIGITS = set(string.digits)
16
+ ASCII_PRINTABLES = {ord(x) for x in string.printable}
17
+ ASCII_DIGITS = {ord(x) for x in string.digits}
16
18
 
17
19
 
18
20
  class InlinedWstrcpy(PeepholeOptimizationStmtBase):
@@ -23,70 +25,83 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
23
25
  __slots__ = ()
24
26
 
25
27
  NAME = "Simplifying inlined wstrcpy"
26
- stmt_classes = (Assignment,)
28
+ stmt_classes = (Assignment, Store)
27
29
 
28
- def optimize(self, stmt: Assignment, stmt_idx: int | None = None, block=None, **kwargs):
30
+ def optimize(self, stmt: Assignment | Store, stmt_idx: int | None = None, block=None, **kwargs):
29
31
  if (
30
- isinstance(stmt.dst, VirtualVariable)
32
+ isinstance(stmt, Assignment)
33
+ and isinstance(stmt.dst, VirtualVariable)
31
34
  and stmt.dst.was_stack
32
35
  and isinstance(stmt.src, Const)
33
36
  and isinstance(stmt.src.value, int)
34
37
  ):
35
- r, s = self.is_integer_likely_a_wide_string(stmt.src.value, stmt.src.size, self.project.arch.memory_endness)
36
- if r:
37
- # replace it with a call to strncpy
38
- str_id = self.kb.custom_strings.allocate(s.encode("ascii"))
39
- return Call(
40
- stmt.idx,
41
- "wstrncpy",
42
- args=[
43
- StackBaseOffset(None, self.project.arch.bits, stmt.dst.stack_offset),
44
- Const(None, None, str_id, self.project.arch.bits, custom_string=True),
45
- Const(None, None, len(s), self.project.arch.bits),
46
- ],
47
- **stmt.tags,
48
- )
49
-
50
- # scan forward in the current block to find all consecutive constant stores
51
- if block is not None and stmt_idx is not None:
52
- all_constant_stores: dict[int, tuple[int, Const | None]] = self.collect_constant_stores(block, stmt_idx)
53
- if all_constant_stores:
54
- offsets = sorted(all_constant_stores.keys())
55
- next_offset = min(offsets)
56
- stride = []
57
- for offset in offsets:
58
- if next_offset is not None and offset != next_offset:
59
- next_offset = None
60
- stride = []
61
- stmt_idx_, v = all_constant_stores[offset]
62
- if v is not None:
63
- stride.append((offset, stmt_idx_, v))
64
- next_offset = offset + v.size
65
- else:
66
- next_offset = None
67
- stride = []
68
-
69
- integer, size = self.stride_to_int(stride)
70
- r, s = self.is_integer_likely_a_wide_string(integer, size, Endness.BE)
71
- if r:
72
- # we remove all involved statements whose statement IDs are greater than the current one
73
- for _, stmt_idx_, _ in reversed(stride):
74
- if stmt_idx_ <= stmt_idx:
75
- continue
76
- block.statements[stmt_idx_] = None
77
- block.statements = [ss for ss in block.statements if ss is not None]
78
-
79
- str_id = self.kb.custom_strings.allocate(s.encode("ascii"))
80
- return Call(
81
- stmt.idx,
82
- "wstrncpy",
83
- args=[
84
- StackBaseOffset(None, self.project.arch.bits, stmt.dst.stack_offset),
85
- Const(None, None, str_id, self.project.arch.bits, custom_string=True),
86
- Const(None, None, len(s), self.project.arch.bits),
87
- ],
88
- **stmt.tags,
89
- )
38
+ dst = StackBaseOffset(None, self.project.arch.bits, stmt.dst.stack_offset)
39
+ value_size = stmt.src.size
40
+ value = stmt.src.value
41
+ elif isinstance(stmt, Store) and isinstance(stmt.data, Const) and isinstance(stmt.data.value, int):
42
+ dst = stmt.addr
43
+ value_size = stmt.data.size
44
+ value = stmt.data.value
45
+ else:
46
+ return None
47
+
48
+ r, s = self.is_integer_likely_a_wide_string(value, value_size, self.project.arch.memory_endness)
49
+ if r:
50
+ # replace it with a call to strncpy
51
+ str_id = self.kb.custom_strings.allocate(s)
52
+ wstr_type = SimTypePointer(SimTypeWideChar()).with_arch(self.project.arch)
53
+ return Call(
54
+ stmt.idx,
55
+ "wstrncpy",
56
+ args=[
57
+ dst,
58
+ Const(None, None, str_id, self.project.arch.bits, custom_string=True, type=wstr_type),
59
+ Const(None, None, len(s) // 2, self.project.arch.bits),
60
+ ],
61
+ **stmt.tags,
62
+ )
63
+
64
+ # scan forward in the current block to find all consecutive constant stores
65
+ if block is not None and stmt_idx is not None:
66
+ all_constant_stores: dict[int, tuple[int, Const | None]] = self.collect_constant_stores(block, stmt_idx)
67
+ if all_constant_stores:
68
+ offsets = sorted(all_constant_stores.keys())
69
+ next_offset = min(offsets)
70
+ stride = []
71
+ for offset in offsets:
72
+ if next_offset is not None and offset != next_offset:
73
+ next_offset = None
74
+ stride = []
75
+ stmt_idx_, v = all_constant_stores[offset]
76
+ if v is not None:
77
+ stride.append((offset, stmt_idx_, v))
78
+ next_offset = offset + v.size
79
+ else:
80
+ next_offset = None
81
+ stride = []
82
+
83
+ integer, size = self.stride_to_int(stride)
84
+ r, s = self.is_integer_likely_a_wide_string(integer, size, Endness.BE, min_length=3)
85
+ if r:
86
+ # we remove all involved statements whose statement IDs are greater than the current one
87
+ for _, stmt_idx_, _ in reversed(stride):
88
+ if stmt_idx_ <= stmt_idx:
89
+ continue
90
+ block.statements[stmt_idx_] = None
91
+ block.statements = [ss for ss in block.statements if ss is not None]
92
+
93
+ str_id = self.kb.custom_strings.allocate(s)
94
+ wstr_type = SimTypePointer(SimTypeWideChar()).with_arch(self.project.arch)
95
+ return Call(
96
+ stmt.idx,
97
+ "wstrncpy",
98
+ args=[
99
+ dst,
100
+ Const(None, None, str_id, self.project.arch.bits, custom_string=True, type=wstr_type),
101
+ Const(None, None, len(s) // 2, self.project.arch.bits),
102
+ ],
103
+ **stmt.tags,
104
+ )
90
105
 
91
106
  return None
92
107
 
@@ -103,68 +118,131 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
103
118
 
104
119
  def collect_constant_stores(self, block, starting_stmt_idx: int) -> dict[int, tuple[int, Const | None]]:
105
120
  r = {}
121
+ expected_store_varid: int | None = None
122
+ starting_stmt = block.statements[starting_stmt_idx]
123
+ if (
124
+ isinstance(starting_stmt, Assignment)
125
+ and isinstance(starting_stmt.dst, VirtualVariable)
126
+ and starting_stmt.dst.was_stack
127
+ and isinstance(starting_stmt.dst.stack_offset, int)
128
+ ):
129
+ expected_type = "stack"
130
+ elif isinstance(starting_stmt, Store):
131
+ if isinstance(starting_stmt.addr, VirtualVariable):
132
+ expected_store_varid = starting_stmt.addr.varid
133
+ elif (
134
+ isinstance(starting_stmt.addr, BinaryOp)
135
+ and starting_stmt.addr.op == "Add"
136
+ and isinstance(starting_stmt.addr.operands[0], VirtualVariable)
137
+ and isinstance(starting_stmt.addr.operands[1], Const)
138
+ ):
139
+ expected_store_varid = starting_stmt.addr.operands[0].varid
140
+ else:
141
+ expected_store_varid = None
142
+ expected_type = "store"
143
+ else:
144
+ return r
145
+
106
146
  for idx, stmt in enumerate(block.statements):
107
147
  if idx < starting_stmt_idx:
108
148
  continue
109
149
  if (
110
- isinstance(stmt, Assignment)
150
+ expected_type == "stack"
151
+ and isinstance(stmt, Assignment)
111
152
  and isinstance(stmt.dst, VirtualVariable)
112
153
  and stmt.dst.was_stack
113
154
  and isinstance(stmt.dst.stack_offset, int)
114
155
  ):
115
- if isinstance(stmt.src, Const):
116
- r[stmt.dst.stack_offset] = idx, ail_const_to_be(stmt.src, self.project.arch.memory_endness)
156
+ offset = stmt.dst.stack_offset
157
+ value = (
158
+ ail_const_to_be(stmt.src, self.project.arch.memory_endness) if isinstance(stmt.src, Const) else None
159
+ )
160
+ elif expected_type == "store" and isinstance(stmt, Store):
161
+ if isinstance(stmt.addr, VirtualVariable) and stmt.addr.varid == expected_store_varid:
162
+ offset = 0
163
+ elif (
164
+ isinstance(stmt.addr, BinaryOp)
165
+ and stmt.addr.op == "Add"
166
+ and isinstance(stmt.addr.operands[0], VirtualVariable)
167
+ and isinstance(stmt.addr.operands[1], Const)
168
+ and stmt.addr.operands[0].varid == expected_store_varid
169
+ ):
170
+ offset = stmt.addr.operands[1].value
117
171
  else:
118
- r[stmt.dst.stack_offset] = idx, None
172
+ offset = None
173
+ value = (
174
+ ail_const_to_be(stmt.data, self.project.arch.memory_endness)
175
+ if isinstance(stmt.data, Const)
176
+ else None
177
+ )
178
+ else:
179
+ continue
180
+
181
+ if offset is not None:
182
+ r[offset] = idx, value
119
183
 
120
184
  return r
121
185
 
122
186
  @staticmethod
123
- def even_offsets_are_zero(lst: list[str]) -> bool:
124
- return all(ch == "\x00" for i, ch in enumerate(lst) if i % 2 == 0)
187
+ def even_offsets_are_zero(lst: list[int]) -> bool:
188
+ if len(lst) >= 2 and lst[-1] == 0 and lst[-2] == 0:
189
+ lst = lst[:-2]
190
+ return all((ch == 0 if i % 2 == 0 else ch != 0) for i, ch in enumerate(lst))
125
191
 
126
192
  @staticmethod
127
- def odd_offsets_are_zero(lst: list[str]) -> bool:
128
- return all(ch == "\x00" for i, ch in enumerate(lst) if i % 2 == 1)
193
+ def odd_offsets_are_zero(lst: list[int]) -> bool:
194
+ if len(lst) >= 2 and lst[-1] == 0 and lst[-2] == 0:
195
+ lst = lst[:-2]
196
+ return all((ch == 0 if i % 2 == 1 else ch != 0) for i, ch in enumerate(lst))
129
197
 
130
198
  @staticmethod
131
199
  def is_integer_likely_a_wide_string(
132
200
  v: int, size: int, endness: Endness, min_length: int = 4
133
- ) -> tuple[bool, str | None]:
201
+ ) -> tuple[bool, bytes | None]:
134
202
  # we need at least four bytes of printable characters
135
203
 
136
- chars = []
204
+ chars: list[int] = []
137
205
  if endness == Endness.LE:
138
206
  while v != 0:
139
207
  byt = v & 0xFF
140
- if byt != 0 and chr(byt) not in ASCII_PRINTABLES:
208
+ if byt != 0 and byt not in ASCII_PRINTABLES:
141
209
  return False, None
142
- chars.append(chr(byt))
210
+ chars.append(byt)
143
211
  v >>= 8
212
+ if len(chars) % 2 == 1:
213
+ chars.append(0)
144
214
 
145
215
  elif endness == Endness.BE:
146
216
  for _ in range(size):
147
217
  byt = v & 0xFF
148
218
  v >>= 8
149
- if byt != 0 and chr(byt) not in ASCII_PRINTABLES:
219
+ if byt != 0 and byt not in ASCII_PRINTABLES:
150
220
  return False, None
151
- chars.append(chr(byt))
221
+ chars.append(byt)
152
222
  chars.reverse()
153
223
  else:
154
224
  # unsupported endness
155
225
  return False, None
156
226
 
157
- if InlinedWstrcpy.even_offsets_are_zero(chars):
158
- chars = [ch for i, ch in enumerate(chars) if i % 2 == 1]
159
- elif InlinedWstrcpy.odd_offsets_are_zero(chars):
160
- chars = [ch for i, ch in enumerate(chars) if i % 2 == 0]
161
- else:
227
+ if not (InlinedWstrcpy.even_offsets_are_zero(chars) or InlinedWstrcpy.odd_offsets_are_zero(chars)):
162
228
  return False, None
163
229
 
164
- if chars and chars[-1] == "\x00":
230
+ if chars and len(chars) >= 2 and chars[-1] == 0 and chars[-2] == 0:
165
231
  chars = chars[:-1]
166
- if len(chars) >= min_length and all(ch in ASCII_PRINTABLES for ch in chars):
167
- if len(chars) <= 4 and all(ch in ASCII_DIGITS for ch in chars):
232
+ if len(chars) >= min_length * 2 and all((ch == 0 or ch in ASCII_PRINTABLES) for ch in chars):
233
+ if len(chars) <= 4 * 2 and all((ch == 0 or ch in ASCII_DIGITS) for ch in chars):
168
234
  return False, None
169
- return True, "".join(chars)
235
+ return True, bytes(chars)
170
236
  return False, None
237
+
238
+ @staticmethod
239
+ def is_inlined_wstrncpy(stmt: Statement) -> bool:
240
+ return (
241
+ isinstance(stmt, Call)
242
+ and isinstance(stmt.target, str)
243
+ and stmt.target == "wstrncpy"
244
+ and stmt.args is not None
245
+ and len(stmt.args) == 3
246
+ and isinstance(stmt.args[1], Const)
247
+ and hasattr(stmt.args[1], "custom_string")
248
+ )
@@ -0,0 +1,113 @@
1
+ # pylint:disable=arguments-differ
2
+ from __future__ import annotations
3
+
4
+ from angr.ailment.expression import Expression, BinaryOp, Const, Register, StackBaseOffset, UnaryOp, VirtualVariable
5
+ from angr.ailment.statement import Call, Store
6
+
7
+ from angr.sim_type import SimTypePointer, SimTypeWideChar
8
+ from .base import PeepholeOptimizationMultiStmtBase
9
+ from .inlined_wstrcpy import InlinedWstrcpy
10
+
11
+
12
+ class InlinedWstrcpyConsolidation(PeepholeOptimizationMultiStmtBase):
13
+ """
14
+ Consolidate multiple inlined wstrcpy/wstrncpy calls.
15
+ """
16
+
17
+ __slots__ = ()
18
+
19
+ NAME = "Consolidate multiple inlined wstrncpy calls"
20
+ stmt_classes = ((Call, Call), (Call, Store))
21
+
22
+ def optimize( # type:ignore
23
+ self, stmts: list[Call], stmt_idx: int | None = None, block=None, **kwargs
24
+ ): # pylint:disable=unused-argument
25
+ last_stmt, stmt = stmts
26
+ if InlinedWstrcpy.is_inlined_wstrncpy(last_stmt):
27
+ assert last_stmt.args is not None
28
+ assert self.kb is not None
29
+ s_last: bytes = self.kb.custom_strings[last_stmt.args[1].value]
30
+ addr_last = last_stmt.args[0]
31
+ new_str = None # will be set if consolidation should happen
32
+
33
+ if isinstance(stmt, Call) and InlinedWstrcpy.is_inlined_wstrncpy(stmt):
34
+ assert stmt.args is not None
35
+ # consolidating two calls
36
+ s_curr: bytes = self.kb.custom_strings[stmt.args[1].value]
37
+ addr_curr = stmt.args[0]
38
+ # determine if the two addresses are consecutive
39
+ delta = self._get_delta(addr_last, addr_curr)
40
+ if delta is not None and delta == len(s_last):
41
+ # consolidate both calls!
42
+ new_str = s_last + s_curr
43
+ elif isinstance(stmt, Store) and isinstance(stmt.data, Const) and isinstance(stmt.data.value, int):
44
+ # consolidating a call and a store, in case the store statement is storing the suffix of a string (but
45
+ # the suffix is too short to qualify an inlined strcpy optimization)
46
+ addr_curr = stmt.addr
47
+ delta = self._get_delta(addr_last, addr_curr)
48
+ if delta is not None and delta == len(s_last):
49
+ if stmt.size == 2 and stmt.data.value == 0:
50
+ # it's probably the terminating null byte
51
+ r, s = True, b"\x00\x00"
52
+ else:
53
+ r, s = InlinedWstrcpy.is_integer_likely_a_wide_string(
54
+ stmt.data.value, stmt.size, stmt.endness, min_length=1 # type:ignore
55
+ )
56
+ if r and s is not None:
57
+ new_str = s_last + s
58
+
59
+ if new_str is not None:
60
+ assert self.project is not None
61
+ wstr_type = SimTypePointer(SimTypeWideChar()).with_arch(self.project.arch)
62
+ if new_str.endswith(b"\x00\x00"):
63
+ call_name = "wstrcpy"
64
+ new_str_idx = self.kb.custom_strings.allocate(new_str[:-2])
65
+ args = [
66
+ last_stmt.args[0],
67
+ Const(None, None, new_str_idx, last_stmt.args[0].bits, custom_string=True, type=wstr_type),
68
+ ]
69
+ prototype = None
70
+ else:
71
+ call_name = "wstrncpy"
72
+ new_str_idx = self.kb.custom_strings.allocate(new_str)
73
+ args = [
74
+ last_stmt.args[0],
75
+ Const(None, None, new_str_idx, last_stmt.args[0].bits, custom_string=True, type=wstr_type),
76
+ Const(None, None, len(new_str) // 2, self.project.arch.bits),
77
+ ]
78
+ prototype = None
79
+
80
+ return [Call(stmt.idx, call_name, args=args, prototype=prototype, **stmt.tags)]
81
+
82
+ return None
83
+
84
+ @staticmethod
85
+ def _parse_addr(addr: Expression) -> tuple[Expression, int]:
86
+ if isinstance(addr, Register):
87
+ return addr, 0
88
+ if isinstance(addr, StackBaseOffset):
89
+ return StackBaseOffset(None, addr.bits, 0), addr.offset
90
+ if (
91
+ isinstance(addr, UnaryOp)
92
+ and addr.op == "Reference"
93
+ and isinstance(addr.operand, VirtualVariable)
94
+ and addr.operand.was_stack
95
+ ):
96
+ return StackBaseOffset(None, addr.bits, 0), addr.operand.stack_offset
97
+ if isinstance(addr, BinaryOp):
98
+ if addr.op == "Add" and isinstance(addr.operands[1], Const) and isinstance(addr.operands[1].value, int):
99
+ base_0, offset_0 = InlinedWstrcpyConsolidation._parse_addr(addr.operands[0])
100
+ return base_0, offset_0 + addr.operands[1].value
101
+ if addr.op == "Sub" and isinstance(addr.operands[1], Const) and isinstance(addr.operands[1].value, int):
102
+ base_0, offset_0 = InlinedWstrcpyConsolidation._parse_addr(addr.operands[0])
103
+ return base_0, offset_0 - addr.operands[1].value
104
+
105
+ return addr, 0
106
+
107
+ @staticmethod
108
+ def _get_delta(addr_0: Expression, addr_1: Expression) -> int | None:
109
+ base_0, offset_0 = InlinedWstrcpyConsolidation._parse_addr(addr_0)
110
+ base_1, offset_1 = InlinedWstrcpyConsolidation._parse_addr(addr_1)
111
+ if base_0.likes(base_1):
112
+ return offset_1 - offset_0
113
+ return None
@@ -2230,52 +2230,68 @@ class CConstant(CExpression):
2230
2230
  return f'{prefix}"{base_str}"'
2231
2231
 
2232
2232
  def c_repr_chunks(self, indent=0, asexpr=False):
2233
+
2234
+ def _default_output(v) -> str | None:
2235
+ if isinstance(v, MemoryData) and v.sort == MemoryDataSort.String:
2236
+ return CConstant.str_to_c_str(v.content.decode("utf-8"))
2237
+ if isinstance(v, Function):
2238
+ return get_cpp_function_name(v.demangled_name)
2239
+ if isinstance(v, str):
2240
+ return CConstant.str_to_c_str(v)
2241
+ if isinstance(v, bytes):
2242
+ return CConstant.str_to_c_str(v.replace(b"\x00", b"").decode("utf-8"))
2243
+ return None
2244
+
2233
2245
  if self.collapsed:
2234
2246
  yield "...", self
2235
2247
  return
2236
2248
 
2237
- # default priority: string references -> variables -> other reference values
2238
2249
  if self.reference_values is not None:
2239
- for _ty, v in self.reference_values.items(): # pylint:disable=unused-variable
2240
- if isinstance(v, MemoryData) and v.sort == MemoryDataSort.String:
2241
- yield CConstant.str_to_c_str(v.content.decode("utf-8")), self
2242
- return
2243
- elif isinstance(v, Function):
2244
- yield get_cpp_function_name(v.demangled_name), self
2250
+ if self._type is not None and self._type in self.reference_values:
2251
+ if isinstance(self._type, SimTypeInt):
2252
+ if isinstance(self.reference_values[self._type], int):
2253
+ yield self.fmt_int(self.reference_values[self._type]), self
2254
+ return
2255
+ yield hex(self.reference_values[self._type]), self
2245
2256
  return
2246
- elif isinstance(v, str):
2257
+ elif isinstance(self._type, SimTypePointer) and isinstance(self._type.pts_to, SimTypeChar):
2258
+ refval = self.reference_values[self._type]
2259
+ if isinstance(refval, MemoryData):
2260
+ v = refval.content.decode("utf-8")
2261
+ elif isinstance(refval, bytes):
2262
+ v = refval.decode("latin1")
2263
+ else:
2264
+ # it must be a string
2265
+ v = refval
2266
+ assert isinstance(v, str)
2247
2267
  yield CConstant.str_to_c_str(v), self
2248
2268
  return
2249
- elif isinstance(v, bytes):
2250
- yield CConstant.str_to_c_str(v.replace(b"\x00", b"").decode("utf-8")), self
2269
+ elif isinstance(self._type, SimTypePointer) and isinstance(self._type.pts_to, SimTypeWideChar):
2270
+ refval = self.reference_values[self._type]
2271
+ v = (
2272
+ refval.content.decode("utf_16_le")
2273
+ if isinstance(refval, MemoryData)
2274
+ else refval.decode("utf_16_le")
2275
+ ) # it's a string
2276
+ yield CConstant.str_to_c_str(v, prefix="L"), self
2251
2277
  return
2252
-
2253
- if self.reference_values is not None and self._type is not None and self._type in self.reference_values:
2254
- if isinstance(self._type, SimTypeInt):
2255
- if isinstance(self.reference_values[self._type], int):
2256
- yield self.fmt_int(self.reference_values[self._type]), self
2257
- return
2258
- yield hex(self.reference_values[self._type]), self
2259
- elif isinstance(self._type, SimTypePointer) and isinstance(self._type.pts_to, SimTypeChar):
2260
- refval = self.reference_values[self._type]
2261
- if isinstance(refval, MemoryData):
2262
- v = refval.content.decode("utf-8")
2263
2278
  else:
2264
- # it's a string
2265
- v = refval
2266
- assert isinstance(v, str)
2267
- yield CConstant.str_to_c_str(v), self
2268
- elif isinstance(self._type, SimTypePointer) and isinstance(self._type.pts_to, SimTypeWideChar):
2269
- refval = self.reference_values[self._type]
2270
- v = refval.content.decode("utf_16_le") if isinstance(refval, MemoryData) else refval # it's a string
2271
- yield CConstant.str_to_c_str(v, prefix="L"), self
2272
- else:
2273
- if isinstance(self.reference_values[self._type], int):
2274
- yield self.fmt_int(self.reference_values[self._type]), self
2279
+ if isinstance(self.reference_values[self._type], int):
2280
+ yield self.fmt_int(self.reference_values[self._type]), self
2281
+ return
2282
+ o = _default_output(self.reference_values[self.type])
2283
+ if o is not None:
2284
+ yield o, self
2285
+ return
2286
+
2287
+ # default priority: string references -> variables -> other reference values
2288
+ for _ty, v in self.reference_values.items(): # pylint:disable=unused-variable
2289
+ o = _default_output(v)
2290
+ if o is not None:
2291
+ yield o, self
2275
2292
  return
2276
- yield self.reference_values[self.type], self
2277
2293
 
2278
- elif isinstance(self.value, int) and self.value == 0 and isinstance(self.type, SimTypePointer):
2294
+ if isinstance(self.value, int) and self.value == 0 and isinstance(self.type, SimTypePointer):
2279
2295
  # print NULL instead
2280
2296
  yield "NULL", self
2281
2297
 
@@ -3622,10 +3638,10 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3622
3638
  if type_ is None and hasattr(expr, "type"):
3623
3639
  type_ = expr.type
3624
3640
 
3625
- if type_ is None and reference_values is None and hasattr(expr, "reference_values"):
3641
+ if reference_values is None and hasattr(expr, "reference_values"):
3626
3642
  reference_values = expr.reference_values.copy()
3627
- if len(reference_values) == 1: # type: ignore
3628
- type_ = next(iter(reference_values)) # type: ignore
3643
+ if type_ is None and reference_values is not None and len(reference_values) == 1: # type: ignore
3644
+ type_ = next(iter(reference_values)) # type: ignore
3629
3645
 
3630
3646
  if reference_values is None:
3631
3647
  reference_values = {}
@@ -3714,10 +3730,10 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3714
3730
  offset = getattr(expr, "reference_variable_offset", 0)
3715
3731
  var_access = self._access_constant_offset_reference(self._get_variable_reference(cvar), offset, None)
3716
3732
 
3717
- if var_access is not None and expr.value >= self.min_data_addr:
3718
- return var_access
3719
-
3720
- reference_values["offset"] = var_access
3733
+ if var_access is not None:
3734
+ if expr.value >= self.min_data_addr:
3735
+ return var_access
3736
+ reference_values["offset"] = var_access
3721
3737
  return CConstant(expr.value, type_, reference_values=reference_values, tags=expr.tags, codegen=self)
3722
3738
 
3723
3739
  def _handle_Expr_UnaryOp(self, expr, **kwargs):
@@ -30,6 +30,9 @@ class RegVVarPredicate:
30
30
  self.arch = arch
31
31
 
32
32
  def _get_call_clobbered_regs(self, stmt: Call) -> set[int]:
33
+ if isinstance(stmt.target, str):
34
+ # pseudo calls do not clobber any registers
35
+ return set()
33
36
  cc = stmt.calling_convention
34
37
  if cc is None:
35
38
  # get the default calling convention
@@ -1,25 +1,45 @@
1
1
  from __future__ import annotations
2
+
2
3
  from angr.serializable import Serializable
3
4
 
4
5
 
5
6
  class IndirectJumpType:
7
+ """
8
+ The type of an indirect jump or call.
9
+ """
10
+
6
11
  Jumptable_AddressLoadedFromMemory = 0
7
12
  Jumptable_AddressComputed = 1
8
13
  Vtable = 3
9
14
  Unknown = 255
10
15
 
11
16
 
17
+ class JumptableInfo:
18
+ """
19
+ Describes a jump table or a vtable.
20
+ """
21
+
22
+ __slots__ = ("addr", "entries", "entry_size", "size")
23
+
24
+ def __init__(self, addr: int | None, size: int, entry_size: int, entries: list[int]):
25
+ self.addr = addr
26
+ self.size = size
27
+ self.entry_size = entry_size
28
+ self.entries = entries
29
+
30
+
12
31
  class IndirectJump(Serializable):
32
+ """
33
+ Describes an indirect jump or call site.
34
+ """
35
+
13
36
  __slots__ = (
14
37
  "addr",
15
38
  "func_addr",
16
39
  "ins_addr",
17
40
  "jumpkind",
18
41
  "jumptable",
19
- "jumptable_addr",
20
- "jumptable_entries",
21
- "jumptable_entry_size",
22
- "jumptable_size",
42
+ "jumptables",
23
43
  "resolved_targets",
24
44
  "stmt_idx",
25
45
  "type",
@@ -47,12 +67,56 @@ class IndirectJump(Serializable):
47
67
  self.stmt_idx = stmt_idx
48
68
  self.resolved_targets = set() if resolved_targets is None else set(resolved_targets)
49
69
  self.jumptable = jumptable
50
- self.jumptable_addr = jumptable_addr
51
- self.jumptable_size = jumptable_size
52
- self.jumptable_entry_size = jumptable_entry_size
53
- self.jumptable_entries = jumptable_entries
70
+ self.jumptables: list[JumptableInfo] = []
71
+ if (
72
+ jumptable_addr is not None
73
+ and jumptable_size is not None
74
+ and jumptable_entry_size is not None
75
+ and jumptable_entries is not None
76
+ ):
77
+ self.add_jumptable(jumptable_addr, jumptable_size, jumptable_entry_size, jumptable_entries)
54
78
  self.type = type_
55
79
 
80
+ def add_jumptable(
81
+ self,
82
+ addr: int | None,
83
+ size: int,
84
+ entry_size: int,
85
+ entries: list[int],
86
+ is_primary: bool = False,
87
+ ) -> None:
88
+ ji = JumptableInfo(addr, size, entry_size, entries)
89
+ if is_primary:
90
+ self.jumptables.insert(0, ji)
91
+ else:
92
+ self.jumptables.append(ji)
93
+
94
+ # for compatibility convenience
95
+
96
+ @property
97
+ def jumptable_addr(self) -> int | None:
98
+ if self.jumptables:
99
+ return self.jumptables[0].addr
100
+ return None
101
+
102
+ @property
103
+ def jumptable_size(self) -> int | None:
104
+ if self.jumptables:
105
+ return self.jumptables[0].size
106
+ return None
107
+
108
+ @property
109
+ def jumptable_entry_size(self) -> int | None:
110
+ if self.jumptables:
111
+ return self.jumptables[0].entry_size
112
+ return None
113
+
114
+ @property
115
+ def jumptable_entries(self) -> list[int] | None:
116
+ if self.jumptables:
117
+ return self.jumptables[0].entries
118
+ return None
119
+
56
120
  def __repr__(self):
57
121
  status = ""
58
122
  if self.jumptable or self.jumptable_entries:
@@ -61,5 +125,7 @@ class IndirectJump(Serializable):
61
125
  status += f"@{self.jumptable_addr:#08x}"
62
126
  if self.jumptable_entries is not None:
63
127
  status += f" with {len(self.jumptable_entries)} entries"
128
+ if len(self.jumptables) > 1:
129
+ status += f" (+{len(self.jumptables)-1} jumptables)"
64
130
 
65
131
  return "<IndirectJump {:#08x} - ins {:#08x}{}>".format(self.addr, self.ins_addr, " " + status if status else "")
angr/rustylib.abi3.so CHANGED
Binary file
angr/unicornlib.dylib CHANGED
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: angr
3
- Version: 9.2.172
3
+ Version: 9.2.173
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
  License: BSD-2-Clause
6
6
  Project-URL: Homepage, https://angr.io/
@@ -16,12 +16,12 @@ Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
17
  Requires-Dist: cxxheaderparser
18
18
  Requires-Dist: GitPython
19
- Requires-Dist: archinfo==9.2.172
19
+ Requires-Dist: archinfo==9.2.173
20
20
  Requires-Dist: cachetools
21
21
  Requires-Dist: capstone==5.0.3
22
22
  Requires-Dist: cffi>=1.14.0
23
- Requires-Dist: claripy==9.2.172
24
- Requires-Dist: cle==9.2.172
23
+ Requires-Dist: claripy==9.2.173
24
+ Requires-Dist: cle==9.2.173
25
25
  Requires-Dist: mulpyplexer
26
26
  Requires-Dist: networkx!=2.8.1,>=2.0
27
27
  Requires-Dist: protobuf>=5.28.2
@@ -30,7 +30,7 @@ Requires-Dist: pycparser>=2.18
30
30
  Requires-Dist: pydemumble
31
31
  Requires-Dist: pyformlang
32
32
  Requires-Dist: pypcode<4.0,>=3.2.1
33
- Requires-Dist: pyvex==9.2.172
33
+ Requires-Dist: pyvex==9.2.173
34
34
  Requires-Dist: rich>=13.1.0
35
35
  Requires-Dist: sortedcontainers
36
36
  Requires-Dist: sympy
@@ -1,23 +1,23 @@
1
- angr-9.2.172.dist-info/RECORD,,
2
- angr-9.2.172.dist-info/WHEEL,sha256=wTy_3c4XcOAcqIE15cpeRqeJHiJiSBH-pmU5VVW1EO8,137
3
- angr-9.2.172.dist-info/entry_points.txt,sha256=Vjh1C8PMyr5dZFMnik5WkEP01Uwr2T73I3a6N32sgQU,44
4
- angr-9.2.172.dist-info/top_level.txt,sha256=dKw0KWTbwLXytFvv15oAAG4sUs3ey47tt6DorJG9-hw,5
5
- angr-9.2.172.dist-info/METADATA,sha256=55ffKaXpTmUAExTjDVpK_UPO5MKEwSHXIQcMUDrnARY,4343
6
- angr-9.2.172.dist-info/licenses/LICENSE,sha256=PmWf0IlSz6Jjp9n7nyyBQA79Q5C2ma68LRykY1V3GF0,1456
1
+ angr-9.2.173.dist-info/RECORD,,
2
+ angr-9.2.173.dist-info/WHEEL,sha256=wTy_3c4XcOAcqIE15cpeRqeJHiJiSBH-pmU5VVW1EO8,137
3
+ angr-9.2.173.dist-info/entry_points.txt,sha256=Vjh1C8PMyr5dZFMnik5WkEP01Uwr2T73I3a6N32sgQU,44
4
+ angr-9.2.173.dist-info/top_level.txt,sha256=dKw0KWTbwLXytFvv15oAAG4sUs3ey47tt6DorJG9-hw,5
5
+ angr-9.2.173.dist-info/METADATA,sha256=iZFZTkufSw1zmEbcMmoF3paxU1UXWSFzOPAJ4lU_t4c,4343
6
+ angr-9.2.173.dist-info/licenses/LICENSE,sha256=PmWf0IlSz6Jjp9n7nyyBQA79Q5C2ma68LRykY1V3GF0,1456
7
7
  angr/vaults.py,sha256=D_gkDegCyPlZMKGC5E8zINYAaZfSXNWbmhX0rXCYpvM,9718
8
- angr/unicornlib.dylib,sha256=E4kM6p5IQ9XGbL7Zh12CarXRVNVKccJiNPqPjHH-VjQ,264656
8
+ angr/unicornlib.dylib,sha256=ap3ME0HcxUPSsyrifxavZ6J_v9nKZSz1chr2amCB8Jw,264656
9
9
  angr/state_hierarchy.py,sha256=qDQCUGXmQm3vOxE3CSoiqTH4OAFFOWZZt9BLhNpeOhA,8484
10
10
  angr/callable.py,sha256=j9Orwd4H4fPqOYylcEt5GuLGPV7ZOqyA_OYO2bp5PAA,6437
11
11
  angr/sim_type.py,sha256=Z0gWJaTVwjC6I_O7nzwa0DtEXZSFA9ekikm-U2gxCR4,135357
12
12
  angr/knowledge_base.py,sha256=hRoSLuLaOXmddTSF9FN5TVs7liftpBGq_IICz5AaYBk,4533
13
13
  angr/emulator.py,sha256=572e9l-N4VUzUzLKylqpv3JmBvVC5VExi1tLy6MZSoU,4633
14
- angr/rustylib.abi3.so,sha256=Df1Cq53wXQziP6KC27BS7ehr_LOVNNnMwBXNH7VuZMQ,5259788
14
+ angr/rustylib.abi3.so,sha256=GxYgg0Ujk_bP1mpelCeLpUeAKSF1ZUCuAiO7pJ-hk7M,5259788
15
15
  angr/codenode.py,sha256=hCrQRp4Ebb2X6JicNmY1PXo3_Pm8GDxVivVW0Pwe84k,3918
16
16
  angr/graph_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  angr/sim_manager.py,sha256=w7yTfWR-P9yoN5x85eeiNpj9dTrnjpJ3o5aoFpDAPnc,39396
18
18
  angr/serializable.py,sha256=l908phj_KcqopEEL_oCufbP_H6cm3Wc9v-5xdux1-6g,1533
19
19
  angr/code_location.py,sha256=kXNJDEMge9VRHadrK4E6HQ8wDdCaHSXNqyAZuHDEGuM,5397
20
- angr/__init__.py,sha256=ZeGnjkV15b26W_suDwvHXnFGn8nN22iB2dV9D0w5lW4,9246
20
+ angr/__init__.py,sha256=2Ys7dgqv6Ad4nZVxaLf0JjowZ0LJFev07_3vDZ21Y3M,9246
21
21
  angr/blade.py,sha256=OGGW-oggqI9_LvgZhiQuh9Ktkvf3vhRBmH0XviNyZ6o,15801
22
22
  angr/factory.py,sha256=PPNWvTiWaIgzxzyoTr8ObSF-TXp1hCdbY2e-0xBePNc,17815
23
23
  angr/sim_state_options.py,sha256=dsMY3UefvL7yZKXloubMhzUET3N2Crw-Fpw2Vd1ouZQ,12468
@@ -914,7 +914,7 @@ angr/knowledge_plugins/key_definitions/definition.py,sha256=AAePJW3BYV0Ju3ZFdqVJ
914
914
  angr/knowledge_plugins/key_definitions/environment.py,sha256=UbXUgv2vjz_dbG_gF2iNK6ZztKt2vgxov9SXdVEWFXk,3886
915
915
  angr/knowledge_plugins/key_definitions/atoms.py,sha256=dKbhvROB0cKSIZC1Z29MvIUmEHx5Ke6rK1lMgmKNdV8,11149
916
916
  angr/knowledge_plugins/key_definitions/tag.py,sha256=QWtBe5yuMei6t2NRPwolVyUa1XyY2khMeU6pQwb66iQ,1710
917
- angr/knowledge_plugins/cfg/indirect_jump.py,sha256=W3KWpH7Sx-6Z7h_BwQjCK_XfP3ce_MaeAu_Aaq3D3qg,2072
917
+ angr/knowledge_plugins/cfg/indirect_jump.py,sha256=XQjyH8ZhSlRFWLc--QY9Voq0RB7nI2wzeP5COANwoOc,3741
918
918
  angr/knowledge_plugins/cfg/__init__.py,sha256=oU07YZ4TIsoje8qr6nw_nM2NXizEGKuulD1RDxk4PWI,418
919
919
  angr/knowledge_plugins/cfg/memory_data.py,sha256=QLxFZfrtwz8u6UJn1L-Sxa-C8S0Gy9IOlfNfHCLPIow,5056
920
920
  angr/knowledge_plugins/cfg/cfg_model.py,sha256=Z5HOM7xh285gF5DGmQGRSWWD9KJyjXVWLvl0i521OkA,41722
@@ -1120,7 +1120,7 @@ angr/analyses/variable_recovery/engine_vex.py,sha256=5Q2S1jAr7tALa0m0okqBHBe3cUe
1120
1120
  angr/analyses/variable_recovery/variable_recovery_base.py,sha256=Ewd0TzNdZ_gRYXtXjVrJfODNABMMPjnuvMy9-Nnyui0,16813
1121
1121
  angr/analyses/variable_recovery/annotations.py,sha256=2va7cXnRHYqVqXeVt00QanxfAo3zanL4BkAcC0-Bk20,1438
1122
1122
  angr/analyses/variable_recovery/engine_base.py,sha256=MJ6h-dq_0r-3I3ZOhR8E4So2VqxlyudNeSrAHyQCNRg,53171
1123
- angr/analyses/calling_convention/fact_collector.py,sha256=SCdNm-6qfgj-SRnbtPpzzkZBS0nH0Ik3zPn5wLG6-7Y,28480
1123
+ angr/analyses/calling_convention/fact_collector.py,sha256=9qx3jvBBrhKvRoZrCir61KZBqFtduiFzhbHAtWFvMic,28762
1124
1124
  angr/analyses/calling_convention/__init__.py,sha256=bK5VS6AxT5l86LAhTL7l1HUT9IuvXG9x9ikbIohIFoE,194
1125
1125
  angr/analyses/calling_convention/calling_convention.py,sha256=vdGqrv7SQDnO6Rg9rgDuQSUPxHYGRgEeneTEQhGM-2M,46762
1126
1126
  angr/analyses/calling_convention/utils.py,sha256=twkO073RvkkFXnOTc-KYQT1GKUtz0OPjxh0N6AWIriQ,2110
@@ -1159,13 +1159,13 @@ angr/analyses/reaching_definitions/function_handler_library/stdlib.py,sha256=YRN
1159
1159
  angr/analyses/cfg/cfg.py,sha256=dc9M91CaLeEKduYfMwpsT_01x6XyYuoNvgvcDKtbN-I,3177
1160
1160
  angr/analyses/cfg/cfb.py,sha256=HI25OJKs2OUlWkOSG4kLsZQFnBJcfDwSQKp6_ZRsoQY,15353
1161
1161
  angr/analyses/cfg/cfg_job_base.py,sha256=Zshze972MakTsd-licQz77lac17igQaaTsAteHeHhYQ,5974
1162
- angr/analyses/cfg/cfg_fast.py,sha256=e0rl_AIM1ne-GZK7yuDPNkceyNSZIYY77sg0-jvjsyo,232943
1162
+ angr/analyses/cfg/cfg_fast.py,sha256=shJdaaQ_4gAB7yMe6oFNrC-uWIdhbD-z4jqx5_VdSGs,233023
1163
1163
  angr/analyses/cfg/__init__.py,sha256=-w8Vd6FD6rtjlQaQ7MxwmliFgS2zt-kZepAY4gHas04,446
1164
1164
  angr/analyses/cfg/cfg_fast_soot.py,sha256=8YgMtY_8w4nAMcHR6n-q_eFvKwsvNz0anUH7EzIL1B4,25924
1165
1165
  angr/analyses/cfg/cfg_arch_options.py,sha256=_XRewFZ51SeNaxChadb6_ER7-8LW8KXeTIpoP8_iRj0,3506
1166
1166
  angr/analyses/cfg/cfg_emulated.py,sha256=4lKrmGVfCGt8l3Nz9zH6EcUcAVLwyOM7p81DlxUVNGA,148351
1167
1167
  angr/analyses/cfg/cfg_base.py,sha256=eleUmM_znfsl6KV7T2tUmSEy2iLmPsrT3dNB2BYudd4,124964
1168
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py,sha256=lUAzzSl6URNpMTzsTdaBc1xjDYtzZ0ghUFdgwok-_v8,103712
1168
+ angr/analyses/cfg/indirect_jump_resolvers/jumptable.py,sha256=XJKPcZiKAYJQ4YusVx0xPXQfuoi_qdrHM1Wjf_zh2C4,109111
1169
1169
  angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py,sha256=SSwWVKCqMNxdqTeMkLqXk5UFmzgxJDm8H-xLNBr1Hnc,10173
1170
1170
  angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py,sha256=jmCiDkloyyqb6iRfjXBlu2N9uwYhiqeiXWhnUXW27dU,2950
1171
1171
  angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py,sha256=eo9Bn-lVAzsx-Y7ncr647enHmWyAZIehc9_Q6Uq7xc8,15517
@@ -1228,9 +1228,9 @@ angr/analyses/decompiler/region_identifier.py,sha256=kQJ_KCd3Qx9LWStTM_iUNBG10bD
1228
1228
  angr/analyses/decompiler/empty_node_remover.py,sha256=4CdxTM1AVmRoEdRIwJg1YEy10AgkEoRmJ8SU7xGbKnM,7424
1229
1229
  angr/analyses/decompiler/seq_to_blocks.py,sha256=4-tqstendHHO2J0WD3JHQkm8c4c2KG3AO3mYWrn4xvg,569
1230
1230
  angr/analyses/decompiler/__init__.py,sha256=eyxt2UKvPkbuS_l_1GPb0CJ6hrj2wTavh-mVf23wwiQ,1162
1231
- angr/analyses/decompiler/clinic.py,sha256=rGR5ODSEZyHX1cmEuUNPKxK3BNcVAg-97TlppxhdtDs,151349
1231
+ angr/analyses/decompiler/clinic.py,sha256=pULhfkuDYNBT9o5nYWX9fl1sP0RiWBVCUhHDsmUeIPc,151320
1232
1232
  angr/analyses/decompiler/decompilation_cache.py,sha256=06oiG299mVpGOTL54Xy1CUxz5s8QLgYJn5XIvKFLYkU,1566
1233
- angr/analyses/decompiler/block_simplifier.py,sha256=XcX9wsBM4AL_WWqmFrtSUDeSv0a125cC1-Q1NhmTrNE,14777
1233
+ angr/analyses/decompiler/block_simplifier.py,sha256=vjlugXCB3xFYBDBn3LPxOtU1dDc76PpYtVEoju3i9-4,15513
1234
1234
  angr/analyses/decompiler/node_replacer.py,sha256=jJd3XkIwFE07bIbLriJ6_mQEvfhm90C8lqlrL5Mz1Xg,1450
1235
1235
  angr/analyses/decompiler/decompilation_options.py,sha256=bs6CNpU3UxepgBB_9eUH4jriNpGoryyPP0sR1hDWpTk,8477
1236
1236
  angr/analyses/decompiler/region_walker.py,sha256=u0hR0bEX1hSwkv-vejIM1gS-hcX2F2DLsDqpKhQ5_pQ,752
@@ -1245,7 +1245,7 @@ angr/analyses/decompiler/label_collector.py,sha256=fsCkldy8ZKH4FjkREByg-NDmfCd7P
1245
1245
  angr/analyses/decompiler/jumptable_entry_condition_rewriter.py,sha256=f_JyNiSZfoudElfl2kIzONoYCiosR4xYFOe8Q5SkvLg,2176
1246
1246
  angr/analyses/decompiler/structured_codegen/__init__.py,sha256=mxG4yruPAab8735wVgXZ1zu8qFPz-njKe0m5UcywE3o,633
1247
1247
  angr/analyses/decompiler/structured_codegen/dwarf_import.py,sha256=J6V40RuIyKXN7r6ESftIYfoREgmgFavnUL5m3lyTzlM,7072
1248
- angr/analyses/decompiler/structured_codegen/c.py,sha256=ebZzyHrh0Jt6fPL6gi-MDgRoA4OeXtb_NVePMLe2h4A,149613
1248
+ angr/analyses/decompiler/structured_codegen/c.py,sha256=sFizu2EWABRhv_yaBXd85rPhoRIEZNZ6zdLp5Q4XHa8,150180
1249
1249
  angr/analyses/decompiler/structured_codegen/dummy.py,sha256=JZLeovXE-8C-unp2hbejxCG30l-yCx4sWFh7JMF_iRM,570
1250
1250
  angr/analyses/decompiler/structured_codegen/base.py,sha256=mb5d5iQO1N2wMl7QySvfHemXM-e0yQBhjtlmnLsVSgE,5134
1251
1251
  angr/analyses/decompiler/ssailification/rewriting.py,sha256=aIYuFGlroEXqxaf6lZCfodLD2B53Sb8UJgl2nNb4lg8,15076
@@ -1284,7 +1284,7 @@ angr/analyses/decompiler/region_simplifiers/cascading_ifs.py,sha256=kPWajH8__ap-
1284
1284
  angr/analyses/decompiler/region_simplifiers/expr_folding.py,sha256=naCgnDUjdiDsh6dvoNO-VARfbTfaEYpu3EX9HkJ1cqE,31790
1285
1285
  angr/analyses/decompiler/peephole_optimizations/basepointeroffset_and_mask.py,sha256=2Tb4zGnFA5hZH8oI6t1hoRstGDmOBsOoQxf6fU5Ct7A,1105
1286
1286
  angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py,sha256=8gPWhFTcezgO7pZ_v0pxR7pweds4_GrrY82ur6Nrlf8,4796
1287
- angr/analyses/decompiler/peephole_optimizations/cas_intrinsics.py,sha256=B1FJjIWOo12MwV5X1ybpz69U0zkyeSlW4zmCPIZcXv8,4129
1287
+ angr/analyses/decompiler/peephole_optimizations/cas_intrinsics.py,sha256=2A7NZIzZpDCq3i8e72l7c7KHfEwfJvzi5NffoXU_NNE,4559
1288
1288
  angr/analyses/decompiler/peephole_optimizations/remove_redundant_nots.py,sha256=V5Vm1zUGjsauyOYXbUgDfZEgmChLbY8wnvmcRbfdMk0,1278
1289
1289
  angr/analyses/decompiler/peephole_optimizations/bool_expr_xor_1.py,sha256=vLXt0ekjRep4SgaNq1wyxVkBTzOMTa03d3rgkjUOcUg,995
1290
1290
  angr/analyses/decompiler/peephole_optimizations/bswap.py,sha256=fXV_a58W2X30KCanYeSHdZ2yPcfDlyZq_OkYNMkglrg,6420
@@ -1301,7 +1301,7 @@ angr/analyses/decompiler/peephole_optimizations/a_mul_const_sub_a.py,sha256=5Gsq
1301
1301
  angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py,sha256=0R_ja5u2fO_BMSpfSk68sDMfhwpvBpyCBKahQh-SB4w,3997
1302
1302
  angr/analyses/decompiler/peephole_optimizations/rewrite_mips_gp_loads.py,sha256=YMfsqffIzsB7YslHVohBOeOWeNJydsrBowJ_6oD1QyY,1909
1303
1303
  angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py,sha256=KRjv1VUMmzkmax_s1ZM3nz24iqz1wqInMgJn3NR9kd4,1788
1304
- angr/analyses/decompiler/peephole_optimizations/__init__.py,sha256=TSpLThx8U5YK05r779be8SozeTya0zbziPOZDKCGa6M,4930
1304
+ angr/analyses/decompiler/peephole_optimizations/__init__.py,sha256=EbnjFKVoLce23AbmF-06EdW-TzAeoZjn_NHDkqNWATQ,5034
1305
1305
  angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_branch.py,sha256=1pbXLE65KwREUoB9GqCXBgz-BeUrzXxoIRFUYZAnBVA,1133
1306
1306
  angr/analyses/decompiler/peephole_optimizations/remove_redundant_reinterprets.py,sha256=NpjPio84lBFY76hPyvOWChRo1jgFEj9XKmSh_A3A-bg,1430
1307
1307
  angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py,sha256=nhV4URuLjH_G-te15cJJ3O2-9VJvpOnkRJjdHSBRoko,1481
@@ -1327,9 +1327,10 @@ angr/analyses/decompiler/peephole_optimizations/invert_negated_logical_conjuctio
1327
1327
  angr/analyses/decompiler/peephole_optimizations/rol_ror.py,sha256=hrtAJaWTZgphP6Wex50uz9vHIBeXy1ie5M5CBSruY7Y,5144
1328
1328
  angr/analyses/decompiler/peephole_optimizations/conv_a_sub0_shr_and.py,sha256=4fZUQGdEY2qVANb6xQWZJRf5N7X78R_gyECxzhC_5vU,2384
1329
1329
  angr/analyses/decompiler/peephole_optimizations/coalesce_same_cascading_ifs.py,sha256=--C1JQluHt8ltdfUPBHvRD3SjW_ZcBU3oWdFwpCtpuw,1072
1330
- angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py,sha256=irbBK2HB75f27L2EnHPuwDHumz1GBYqVwB96zoe-SFM,6787
1330
+ angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py,sha256=rR3eC_pjCVBuc8GuWzJJkn6h8c964ODf-5uiwlncwVE,9896
1331
1331
  angr/analyses/decompiler/peephole_optimizations/coalesce_adjacent_shrs.py,sha256=fXq-qFe7JUdD5LdtUhoA9AF3LnY-3Jrmo4t3ZRJIIiQ,1414
1332
1332
  angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py,sha256=FUf1bg9nADlwT1upwTKcVhhPcvZ98C-8PlmkWoHqwZ4,4787
1333
+ angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy_consolidation.py,sha256=TsQEpHhyVr7MdiSFkijR6GFMHsuKlmmy9qvSCo32c2U,5409
1333
1334
  angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts_around_comparators.py,sha256=pMdKsNJtAIPqyWsR8cUEyujdF7e7kbqqvVgelVmKtqY,1610
1334
1335
  angr/analyses/decompiler/peephole_optimizations/optimized_div_simplifier.py,sha256=M4GxEWKs6V9aEYejGluZ8w8QpvPKpaESeFFzid88HjE,14208
1335
1336
  angr/analyses/decompiler/peephole_optimizations/a_div_const_add_a_mul_n_div_const.py,sha256=HY6EQkThiyMaahz3bodJUqLBKWY2n4aKGbKyspMXN50,1641
@@ -1398,7 +1399,7 @@ angr/analyses/decompiler/presets/basic.py,sha256=sHT2oalBmINVSZfpEbx4LmK0G1zqbZm
1398
1399
  angr/analyses/s_reaching_definitions/__init__.py,sha256=TyfVplxkJj8FAAAw9wegzJlcrbGwlFpIB23PdCcwrLA,254
1399
1400
  angr/analyses/s_reaching_definitions/s_reaching_definitions.py,sha256=gNdg8xpu5by_McWU8j0g0502yQsO2evkTlben9yimV0,7826
1400
1401
  angr/analyses/s_reaching_definitions/s_rda_model.py,sha256=FJSge_31FFzyzBJA1xm7dQz40TfuNna6v_RWAZMZvi0,5801
1401
- angr/analyses/s_reaching_definitions/s_rda_view.py,sha256=r0UThjO4ZhrlCUuMYflzMoH5spObH25A65-S2koY5vM,13807
1402
+ angr/analyses/s_reaching_definitions/s_rda_view.py,sha256=7o-llkMUJP_ZhnQ4tkCDrzYok4cAOA7PLt2tX9DY8Mo,13929
1402
1403
  angr/analyses/fcp/__init__.py,sha256=E9dxFckDM9DijfU4RRg9SGL6xDKCz7yBBP-XSkS-S9U,115
1403
1404
  angr/analyses/fcp/fcp.py,sha256=djkJsvSja_De7ptNwllmTHjvVl62BFcH_haBhwhzFtw,16373
1404
1405
  angr/analyses/flirt/flirt.py,sha256=UNXtUBs11WafKeMAW2BwqKJLFhOyObqmRhfCqYdsJpc,10762
File without changes