angr 9.2.148__py3-none-manylinux2014_x86_64.whl → 9.2.149__py3-none-manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of angr might be problematic. Click here for more details.

Files changed (55) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/calling_convention/calling_convention.py +42 -2
  3. angr/analyses/cfg/cfg_emulated.py +5 -2
  4. angr/analyses/cfg/cfg_fast.py +48 -46
  5. angr/analyses/decompiler/ail_simplifier.py +65 -32
  6. angr/analyses/decompiler/block_simplifier.py +20 -6
  7. angr/analyses/decompiler/clinic.py +80 -13
  8. angr/analyses/decompiler/dephication/rewriting_engine.py +24 -2
  9. angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
  10. angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +15 -13
  11. angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
  12. angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +165 -0
  13. angr/analyses/decompiler/optimization_passes/engine_base.py +11 -2
  14. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +17 -2
  15. angr/analyses/decompiler/optimization_passes/optimization_pass.py +10 -6
  16. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +99 -30
  17. angr/analyses/decompiler/peephole_optimizations/__init__.py +6 -0
  18. angr/analyses/decompiler/peephole_optimizations/base.py +43 -3
  19. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
  20. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +3 -0
  21. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +4 -1
  22. angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
  23. angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +69 -2
  24. angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
  25. angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
  26. angr/analyses/decompiler/presets/fast.py +2 -0
  27. angr/analyses/decompiler/presets/full.py +2 -0
  28. angr/analyses/decompiler/ssailification/rewriting_engine.py +51 -4
  29. angr/analyses/decompiler/ssailification/ssailification.py +23 -3
  30. angr/analyses/decompiler/ssailification/traversal_engine.py +15 -1
  31. angr/analyses/decompiler/structured_codegen/c.py +141 -10
  32. angr/analyses/decompiler/utils.py +6 -1
  33. angr/analyses/s_reaching_definitions/s_rda_view.py +1 -0
  34. angr/analyses/typehoon/lifter.py +20 -0
  35. angr/analyses/typehoon/simple_solver.py +42 -9
  36. angr/analyses/typehoon/translator.py +4 -1
  37. angr/analyses/typehoon/typeconsts.py +17 -6
  38. angr/analyses/typehoon/typehoon.py +21 -5
  39. angr/analyses/variable_recovery/engine_ail.py +44 -5
  40. angr/analyses/variable_recovery/engine_base.py +35 -12
  41. angr/analyses/variable_recovery/variable_recovery_fast.py +33 -2
  42. angr/calling_conventions.py +23 -5
  43. angr/engines/light/engine.py +7 -0
  44. angr/knowledge_plugins/functions/function.py +68 -0
  45. angr/knowledge_plugins/propagations/states.py +5 -2
  46. angr/knowledge_plugins/variables/variable_manager.py +3 -3
  47. angr/procedures/definitions/__init__.py +1 -1
  48. angr/procedures/definitions/types_stl.py +22 -0
  49. angr/sim_type.py +251 -130
  50. {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/METADATA +7 -7
  51. {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/RECORD +55 -49
  52. {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/WHEEL +1 -1
  53. {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/licenses/LICENSE +3 -0
  54. {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/entry_points.txt +0 -0
  55. {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/top_level.txt +0 -0
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.148"
5
+ __version__ = "9.2.149"
6
6
 
7
7
  if bytes is str:
8
8
  raise Exception(
@@ -13,8 +13,16 @@ import ailment
13
13
 
14
14
  from angr.code_location import ExternalCodeLocation
15
15
 
16
- from angr.calling_conventions import SimFunctionArgument, SimRegArg, SimStackArg, SimCC, default_cc
16
+ from angr.calling_conventions import (
17
+ SimFunctionArgument,
18
+ SimRegArg,
19
+ SimStackArg,
20
+ SimCC,
21
+ default_cc,
22
+ SimCCMicrosoftThiscall,
23
+ )
17
24
  from angr.sim_type import (
25
+ SimTypeCppFunction,
18
26
  SimTypeInt,
19
27
  SimTypeFunction,
20
28
  SimType,
@@ -24,6 +32,7 @@ from angr.sim_type import (
24
32
  SimTypeBottom,
25
33
  SimTypeFloat,
26
34
  SimTypeDouble,
35
+ parse_cpp_file,
27
36
  )
28
37
  from angr.sim_variable import SimStackVariable, SimRegisterVariable
29
38
  from angr.knowledge_plugins.key_definitions.atoms import Register, MemoryLocation, SpOffset
@@ -153,6 +162,13 @@ class CallingConventionAnalysis(Analysis):
153
162
 
154
163
  assert self._function is not None
155
164
 
165
+ demangled_name = self._function.demangled_name
166
+ if demangled_name != self._function.name:
167
+ r_demangled = self._analyze_demangled_name(demangled_name)
168
+ if r_demangled is not None:
169
+ self.cc, self.prototype, self.prototype_libname = r_demangled
170
+ return
171
+
156
172
  if self._function.is_simprocedure:
157
173
  hooker = self.project.hooked_by(self._function.addr)
158
174
  if isinstance(
@@ -348,6 +364,30 @@ class CallingConventionAnalysis(Analysis):
348
364
 
349
365
  return None
350
366
 
367
+ def _analyze_demangled_name(self, name: str) -> tuple[SimCC, SimTypeFunction, str | None] | None:
368
+ """
369
+ Analyze a function with a demangled name. Only C++ names are supported for now.
370
+
371
+ :param name: The demangled name of the function.
372
+ :return: A tuple of the calling convention, the function type, and the library name if available.
373
+ """
374
+ parsed, _ = parse_cpp_file(name)
375
+ if not parsed or len(parsed) != 1:
376
+ return None
377
+ proto = next(iter(parsed.values()))
378
+ if (
379
+ isinstance(proto, SimTypeCppFunction)
380
+ and self.project.simos.name == "Win32"
381
+ and self.project.arch.name == "X86"
382
+ and proto.convention == "__thiscall"
383
+ ):
384
+ cc_cls = SimCCMicrosoftThiscall
385
+ else:
386
+ cc_cls = default_cc(self.project.arch.name, self.project.simos.name)
387
+ assert cc_cls is not None
388
+ cc = cc_cls(self.project.arch)
389
+ return cc, proto, None
390
+
351
391
  def _analyze_function(self) -> tuple[SimCC, SimTypeFunction] | None:
352
392
  """
353
393
  Go over the variable information in variable manager for this function, and return all uninitialized
@@ -681,7 +721,7 @@ class CallingConventionAnalysis(Analysis):
681
721
  # no more arguments
682
722
  temp_args.append(None)
683
723
  elif isinstance(arg_loc, SimStackArg):
684
- if arg_loc.stack_offset in defs_by_stack_offset:
724
+ if arg_loc.stack_offset - cc.STACKARG_SP_DIFF in defs_by_stack_offset:
685
725
  temp_args.append(arg_loc)
686
726
  else:
687
727
  # no more arguments
@@ -2967,10 +2967,13 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
2967
2967
  new_state.options.add(o.DO_RET_EMULATION)
2968
2968
  # Remove bad constraints
2969
2969
  # FIXME: This is so hackish...
2970
- new_state.solver._solver.constraints = [
2970
+ preserved_constraints = [
2971
2971
  c for c in new_state.solver.constraints if c.op != "BoolV" or c.args[0] is not False
2972
2972
  ]
2973
- new_state.solver._solver._result = None
2973
+ new_solver = new_state.solver._solver.blank_copy()
2974
+ new_solver.add(preserved_constraints)
2975
+ new_state.solver._stored_solver = new_solver
2976
+
2974
2977
  # Swap them
2975
2978
  saved_state, job.state = job.state, new_state
2976
2979
  sim_successors, exception_info, _ = self._get_simsuccessors(addr, job)
@@ -4841,66 +4841,68 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
4841
4841
 
4842
4842
  # determine if the function uses ebp as a general purpose register or not
4843
4843
  if addr == func_addr or 0 < addr - func_addr <= 0x20:
4844
- ebp_as_gpr = True
4845
- cap = self._lift(addr, size=cfg_node.size).capstone
4846
- for insn in cap.insns:
4847
- if (
4848
- insn.mnemonic == "mov"
4849
- and len(insn.operands) == 2
4850
- and insn.operands[0].type == capstone.x86.X86_OP_REG
4851
- and insn.operands[1].type == capstone.x86.X86_OP_REG
4852
- ):
4844
+ func = self.kb.functions.get_by_addr(func_addr)
4845
+ if "bp_as_gpr" not in func.info:
4846
+ ebp_as_gpr = True
4847
+ cap = self._lift(addr, size=cfg_node.size).capstone
4848
+ for insn in cap.insns:
4853
4849
  if (
4850
+ insn.mnemonic == "mov"
4851
+ and len(insn.operands) == 2
4852
+ and insn.operands[0].type == capstone.x86.X86_OP_REG
4853
+ and insn.operands[1].type == capstone.x86.X86_OP_REG
4854
+ ):
4855
+ if (
4856
+ insn.operands[0].reg == capstone.x86.X86_REG_EBP
4857
+ and insn.operands[1].reg == capstone.x86.X86_REG_ESP
4858
+ ):
4859
+ ebp_as_gpr = False
4860
+ break
4861
+ elif (
4862
+ insn.mnemonic == "lea"
4863
+ and len(insn.operands) == 2
4864
+ and insn.operands[0].type == capstone.x86.X86_OP_REG
4865
+ and insn.operands[1].type == capstone.x86.X86_OP_MEM
4866
+ ) and (
4854
4867
  insn.operands[0].reg == capstone.x86.X86_REG_EBP
4855
- and insn.operands[1].reg == capstone.x86.X86_REG_ESP
4868
+ and insn.operands[1].mem.base == capstone.x86.X86_REG_ESP
4856
4869
  ):
4857
4870
  ebp_as_gpr = False
4858
4871
  break
4859
- elif (
4860
- insn.mnemonic == "lea"
4861
- and len(insn.operands) == 2
4862
- and insn.operands[0].type == capstone.x86.X86_OP_REG
4863
- and insn.operands[1].type == capstone.x86.X86_OP_MEM
4864
- ) and (
4865
- insn.operands[0].reg == capstone.x86.X86_REG_EBP
4866
- and insn.operands[1].mem.base == capstone.x86.X86_REG_ESP
4867
- ):
4868
- ebp_as_gpr = False
4869
- break
4870
- func = self.kb.functions.get_by_addr(func_addr)
4871
- func.info["bp_as_gpr"] = ebp_as_gpr
4872
+ func.info["bp_as_gpr"] = ebp_as_gpr
4872
4873
 
4873
4874
  elif self.project.arch.name == "AMD64":
4874
4875
  # determine if the function uses rbp as a general purpose register or not
4875
4876
  if addr == func_addr or 0 < addr - func_addr <= 0x20:
4876
- rbp_as_gpr = True
4877
- cap = self._lift(addr, size=cfg_node.size).capstone
4878
- for insn in cap.insns:
4879
- if (
4880
- insn.mnemonic == "mov"
4881
- and len(insn.operands) == 2
4882
- and insn.operands[0].type == capstone.x86.X86_OP_REG
4883
- and insn.operands[1].type == capstone.x86.X86_OP_REG
4884
- ):
4877
+ func = self.kb.functions.get_by_addr(func_addr)
4878
+ if "bp_as_gpr" not in func.info:
4879
+ rbp_as_gpr = True
4880
+ cap = self._lift(addr, size=cfg_node.size).capstone
4881
+ for insn in cap.insns:
4885
4882
  if (
4883
+ insn.mnemonic == "mov"
4884
+ and len(insn.operands) == 2
4885
+ and insn.operands[0].type == capstone.x86.X86_OP_REG
4886
+ and insn.operands[1].type == capstone.x86.X86_OP_REG
4887
+ ):
4888
+ if (
4889
+ insn.operands[0].reg == capstone.x86.X86_REG_RBP
4890
+ and insn.operands[1].reg == capstone.x86.X86_REG_RSP
4891
+ ):
4892
+ rbp_as_gpr = False
4893
+ break
4894
+ elif (
4895
+ insn.mnemonic == "lea"
4896
+ and len(insn.operands) == 2
4897
+ and insn.operands[0].type == capstone.x86.X86_OP_REG
4898
+ and insn.operands[1].type == capstone.x86.X86_OP_MEM
4899
+ ) and (
4886
4900
  insn.operands[0].reg == capstone.x86.X86_REG_RBP
4887
- and insn.operands[1].reg == capstone.x86.X86_REG_RSP
4901
+ and insn.operands[1].mem.base == capstone.x86.X86_REG_RSP
4888
4902
  ):
4889
4903
  rbp_as_gpr = False
4890
4904
  break
4891
- elif (
4892
- insn.mnemonic == "lea"
4893
- and len(insn.operands) == 2
4894
- and insn.operands[0].type == capstone.x86.X86_OP_REG
4895
- and insn.operands[1].type == capstone.x86.X86_OP_MEM
4896
- ) and (
4897
- insn.operands[0].reg == capstone.x86.X86_REG_RBP
4898
- and insn.operands[1].mem.base == capstone.x86.X86_REG_RSP
4899
- ):
4900
- rbp_as_gpr = False
4901
- break
4902
- func = self.kb.functions.get_by_addr(func_addr)
4903
- func.info["bp_as_gpr"] = rbp_as_gpr
4905
+ func.info["bp_as_gpr"] = rbp_as_gpr
4904
4906
 
4905
4907
  def _extract_node_cluster_by_dependency(self, addr, include_successors=False) -> set[int]:
4906
4908
  to_remove = {addr}
@@ -9,7 +9,7 @@ import networkx
9
9
 
10
10
  from ailment import AILBlockWalker
11
11
  from ailment.block import Block
12
- from ailment.statement import Statement, Assignment, Store, Call, ConditionalJump, DirtyStatement
12
+ from ailment.statement import Statement, Assignment, Store, Call, ConditionalJump, DirtyStatement, WeakAssignment
13
13
  from ailment.expression import (
14
14
  Register,
15
15
  Convert,
@@ -247,6 +247,9 @@ class AILSimplifier(Analysis):
247
247
  ):
248
248
  codeloc = CodeLocation(block.addr, stmt_idx, block_idx=block.idx, ins_addr=stmt.ins_addr)
249
249
  equivalence.add(Equivalence(codeloc, stmt.dst, stmt.src))
250
+ elif isinstance(stmt, WeakAssignment):
251
+ codeloc = CodeLocation(block.addr, stmt_idx, block_idx=block.idx, ins_addr=stmt.ins_addr)
252
+ equivalence.add(Equivalence(codeloc, stmt.dst, stmt.src, is_weakassignment=True))
250
253
  elif isinstance(stmt, Call):
251
254
  if isinstance(stmt.ret_expr, (VirtualVariable, Load)):
252
255
  codeloc = CodeLocation(block.addr, stmt_idx, block_idx=block.idx, ins_addr=stmt.ins_addr)
@@ -1172,6 +1175,9 @@ class AILSimplifier(Analysis):
1172
1175
  # register variable = Convert(Call)
1173
1176
  call = eq.atom1
1174
1177
  # call_addr = call.operand.target.value if isinstance(call.operand.target, Const) else None
1178
+ elif eq.is_weakassignment:
1179
+ # variable =w something else
1180
+ call = eq.atom1
1175
1181
  else:
1176
1182
  continue
1177
1183
 
@@ -1196,6 +1202,9 @@ class AILSimplifier(Analysis):
1196
1202
  assert the_def.codeloc.stmt_idx is not None
1197
1203
 
1198
1204
  all_uses: set[tuple[Any, CodeLocation]] = rd.get_vvar_uses_with_expr(the_def.atom)
1205
+ if eq.is_weakassignment:
1206
+ # eliminate the "use" at the weak assignment site
1207
+ all_uses = {use for use in all_uses if use[1] != eq.codeloc}
1199
1208
 
1200
1209
  if len(all_uses) != 1:
1201
1210
  continue
@@ -1218,10 +1227,13 @@ class AILSimplifier(Analysis):
1218
1227
  continue
1219
1228
 
1220
1229
  # check if the use and the definition is within the same supernode
1221
- super_node_blocks = self._get_super_node_blocks(
1222
- addr_and_idx_to_block[(the_def.codeloc.block_addr, the_def.codeloc.block_idx)]
1223
- )
1224
- if u.block_addr not in {b.addr for b in super_node_blocks}:
1230
+ # also we do not allow any calls between the def site and the use site
1231
+ if not self._loc_within_superblock(
1232
+ addr_and_idx_to_block[(the_def.codeloc.block_addr, the_def.codeloc.block_idx)],
1233
+ u.block_addr,
1234
+ u.block_idx,
1235
+ terminate_with_calls=True,
1236
+ ):
1225
1237
  continue
1226
1238
 
1227
1239
  # ensure there are no other calls between the def site and the use site.
@@ -1247,10 +1259,6 @@ class AILSimplifier(Analysis):
1247
1259
  ):
1248
1260
  continue
1249
1261
 
1250
- # check if there are any calls in between the def site and the use site
1251
- if self._count_calls_in_supernodeblocks(super_node_blocks, the_def.codeloc, u) > 0:
1252
- continue
1253
-
1254
1262
  # replace all uses
1255
1263
  old_block = addr_and_idx_to_block.get((u.block_addr, u.block_idx), None)
1256
1264
  if old_block is None:
@@ -1262,7 +1270,7 @@ class AILSimplifier(Analysis):
1262
1270
 
1263
1271
  if isinstance(eq.atom0, VirtualVariable):
1264
1272
  src = used_expr
1265
- dst: Call | Convert = call.copy()
1273
+ dst: Expression = call.copy()
1266
1274
 
1267
1275
  if isinstance(dst, Call) and dst.ret_expr is not None:
1268
1276
  dst_bits = dst.ret_expr.bits
@@ -1272,7 +1280,7 @@ class AILSimplifier(Analysis):
1272
1280
  dst.fp_ret_expr = None
1273
1281
  dst.bits = dst_bits
1274
1282
 
1275
- if src.bits != dst.bits:
1283
+ if src.bits != dst.bits and not eq.is_weakassignment:
1276
1284
  dst = Convert(None, dst.bits, src.bits, False, dst)
1277
1285
  else:
1278
1286
  continue
@@ -1320,6 +1328,42 @@ class AILSimplifier(Analysis):
1320
1328
  break
1321
1329
  return lst
1322
1330
 
1331
+ def _loc_within_superblock(
1332
+ self, start_node: Block, block_addr: int, block_idx: int | None, terminate_with_calls=False
1333
+ ) -> bool:
1334
+ b = start_node
1335
+ if block_addr == b.addr and block_idx == b.idx:
1336
+ return True
1337
+
1338
+ encountered_block_addrs: set[tuple[int, int | None]] = {(b.addr, b.idx)}
1339
+ while True:
1340
+ if terminate_with_calls and b.statements and isinstance(b.statements[-1], Call):
1341
+ return False
1342
+
1343
+ encountered_block_addrs.add((b.addr, b.idx))
1344
+ successors = list(self.func_graph.successors(b))
1345
+ if len(successors) == 0:
1346
+ # did not encounter the block before running out of successors
1347
+ return False
1348
+ if len(successors) == 1:
1349
+ succ = successors[0]
1350
+ # check its predecessors
1351
+ succ_predecessors = list(self.func_graph.predecessors(succ))
1352
+ if len(succ_predecessors) == 1:
1353
+ if (succ.addr, succ.idx) in encountered_block_addrs:
1354
+ # we are about to form a loop - bad!
1355
+ # example: binary ce1897b492c80bf94083dd783aefb413ab1f6d8d4981adce8420f6669d0cb3e1, block
1356
+ # 0x2976EF7.
1357
+ return False
1358
+ if block_addr == succ.addr and block_idx == succ.idx:
1359
+ return True
1360
+ b = succ
1361
+ else:
1362
+ return False
1363
+ else:
1364
+ # too many successors
1365
+ return False
1366
+
1323
1367
  @staticmethod
1324
1368
  def _replace_expr_and_update_block(block, stmt_idx, stmt, src_expr, dst_expr) -> tuple[bool, Block | None]:
1325
1369
  replaced, new_stmt = stmt.replace(src_expr, dst_expr)
@@ -1492,9 +1536,18 @@ class AILSimplifier(Analysis):
1492
1536
  simplified = True
1493
1537
 
1494
1538
  if idx in stmts_to_remove and idx not in stmts_to_keep and not isinstance(stmt, DirtyStatement):
1495
- if isinstance(stmt, (Assignment, Store)):
1539
+ if isinstance(stmt, (Assignment, WeakAssignment, Store)):
1496
1540
  # Special logic for Assignment and Store statements
1497
1541
 
1542
+ # if this statement writes to a virtual variable that must be preserved, we ignore it
1543
+ if (
1544
+ isinstance(stmt, Assignment)
1545
+ and isinstance(stmt.dst, VirtualVariable)
1546
+ and stmt.dst.varid in self._avoid_vvar_ids
1547
+ ):
1548
+ new_statements.append(stmt)
1549
+ continue
1550
+
1498
1551
  # if this statement triggers a call, it should only be removed if it's in self._calls_to_remove
1499
1552
  codeloc = CodeLocation(block.addr, idx, ins_addr=stmt.ins_addr, block_idx=block.idx)
1500
1553
  if codeloc in self._assignments_to_remove:
@@ -1716,26 +1769,6 @@ class AILSimplifier(Analysis):
1716
1769
 
1717
1770
  return False
1718
1771
 
1719
- @staticmethod
1720
- def _count_calls_in_supernodeblocks(blocks: list[Block], start: CodeLocation, end: CodeLocation) -> int:
1721
- """
1722
- Count the number of call statements in a list of blocks for a single super block between two given code
1723
- locations (exclusive).
1724
- """
1725
- calls = 0
1726
- started = False
1727
- for b in blocks:
1728
- if b.addr == start.block_addr:
1729
- started = True
1730
- continue
1731
- if b.addr == end.block_addr:
1732
- started = False
1733
- continue
1734
-
1735
- if started and b.statements and isinstance(b.statements[-1], Call):
1736
- calls += 1
1737
- return calls
1738
-
1739
1772
  @staticmethod
1740
1773
  def _exprs_contain_vvar(exprs: Iterable[Expression], vvar_ids: set[int]) -> bool:
1741
1774
  def _handle_VirtualVariable(expr_idx, expr, stmt_idx, stmt, block): # pylint:disable=unused-argument
@@ -10,6 +10,7 @@ from ailment import AILBlockWalkerBase
10
10
 
11
11
  from angr.code_location import ExternalCodeLocation, CodeLocation
12
12
 
13
+ from angr.knowledge_plugins.key_definitions import atoms
13
14
  from angr.analyses.s_propagator import SPropagatorAnalysis
14
15
  from angr.analyses.s_reaching_definitions import SReachingDefinitionsAnalysis, SRDAModel
15
16
  from angr.analyses import Analysis, register_analysis
@@ -62,6 +63,8 @@ class BlockSimplifier(Analysis):
62
63
  peephole_optimizations: None | (
63
64
  Iterable[type[PeepholeOptimizationStmtBase] | type[PeepholeOptimizationExprBase]]
64
65
  ) = None,
66
+ preserve_vvar_ids: set[int] | None = None,
67
+ type_hints: list[tuple[atoms.VirtualVariable | atoms.MemoryLocation, str]] | None = None,
65
68
  cached_reaching_definitions=None,
66
69
  cached_propagator=None,
67
70
  ):
@@ -74,24 +77,35 @@ class BlockSimplifier(Analysis):
74
77
  self.func_addr = func_addr
75
78
 
76
79
  self._stack_pointer_tracker = stack_pointer_tracker
80
+ self._preserve_vvar_ids = preserve_vvar_ids
81
+ self._type_hints = type_hints
77
82
 
78
83
  if peephole_optimizations is None:
79
- self._expr_peephole_opts = [cls(self.project, self.kb, self.func_addr) for cls in EXPR_OPTS]
80
- self._stmt_peephole_opts = [cls(self.project, self.kb, self.func_addr) for cls in STMT_OPTS]
81
- self._multistmt_peephole_opts = [cls(self.project, self.kb, self.func_addr) for cls in MULTI_STMT_OPTS]
84
+ self._expr_peephole_opts = [
85
+ cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
86
+ for cls in EXPR_OPTS
87
+ ]
88
+ self._stmt_peephole_opts = [
89
+ cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
90
+ for cls in STMT_OPTS
91
+ ]
92
+ self._multistmt_peephole_opts = [
93
+ cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
94
+ for cls in MULTI_STMT_OPTS
95
+ ]
82
96
  else:
83
97
  self._expr_peephole_opts = [
84
- cls(self.project, self.kb, self.func_addr)
98
+ cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
85
99
  for cls in peephole_optimizations
86
100
  if issubclass(cls, PeepholeOptimizationExprBase)
87
101
  ]
88
102
  self._stmt_peephole_opts = [
89
- cls(self.project, self.kb, self.func_addr)
103
+ cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
90
104
  for cls in peephole_optimizations
91
105
  if issubclass(cls, PeepholeOptimizationStmtBase)
92
106
  ]
93
107
  self._multistmt_peephole_opts = [
94
- cls(self.project, self.kb, self.func_addr)
108
+ cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
95
109
  for cls in peephole_optimizations
96
110
  if issubclass(cls, PeepholeOptimizationMultiStmtBase)
97
111
  ]