angr 9.2.123__py3-none-win_amd64.whl → 9.2.125__py3-none-win_amd64.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 (104) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/__init__.py +9 -1
  3. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +11 -8
  4. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_got.py +2 -2
  5. angr/analyses/codecave.py +77 -0
  6. angr/analyses/decompiler/ail_simplifier.py +16 -19
  7. angr/analyses/decompiler/callsite_maker.py +8 -7
  8. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +24 -2
  9. angr/analyses/decompiler/clinic.py +58 -2
  10. angr/analyses/decompiler/condition_processor.py +10 -3
  11. angr/analyses/decompiler/decompilation_cache.py +2 -0
  12. angr/analyses/decompiler/decompiler.py +54 -8
  13. angr/analyses/decompiler/dephication/graph_vvar_mapping.py +10 -2
  14. angr/analyses/decompiler/dephication/rewriting_engine.py +64 -1
  15. angr/analyses/decompiler/expression_narrower.py +5 -1
  16. angr/analyses/decompiler/optimization_passes/__init__.py +3 -0
  17. angr/analyses/decompiler/optimization_passes/div_simplifier.py +4 -1
  18. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +13 -0
  19. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +23 -4
  20. angr/analyses/decompiler/optimization_passes/optimization_pass.py +3 -1
  21. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +8 -5
  22. angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +10 -5
  23. angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +18 -7
  24. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +6 -0
  25. angr/analyses/decompiler/optimization_passes/tag_slicer.py +41 -0
  26. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +2 -0
  27. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +2 -0
  28. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +2 -2
  29. angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +8 -2
  30. angr/analyses/decompiler/region_identifier.py +36 -0
  31. angr/analyses/decompiler/region_simplifiers/loop.py +2 -8
  32. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +9 -3
  33. angr/analyses/decompiler/ssailification/rewriting.py +5 -2
  34. angr/analyses/decompiler/ssailification/rewriting_engine.py +151 -25
  35. angr/analyses/decompiler/ssailification/rewriting_state.py +1 -0
  36. angr/analyses/decompiler/ssailification/ssailification.py +17 -9
  37. angr/analyses/decompiler/ssailification/traversal.py +3 -1
  38. angr/analyses/decompiler/ssailification/traversal_engine.py +35 -8
  39. angr/analyses/decompiler/ssailification/traversal_state.py +1 -0
  40. angr/analyses/decompiler/structured_codegen/c.py +42 -4
  41. angr/analyses/decompiler/structuring/phoenix.py +3 -0
  42. angr/analyses/patchfinder.py +137 -0
  43. angr/analyses/pathfinder.py +282 -0
  44. angr/analyses/propagator/engine_ail.py +10 -3
  45. angr/analyses/reaching_definitions/engine_ail.py +10 -15
  46. angr/analyses/s_propagator.py +16 -9
  47. angr/analyses/s_reaching_definitions/s_rda_view.py +127 -63
  48. angr/analyses/smc.py +159 -0
  49. angr/analyses/variable_recovery/engine_ail.py +14 -0
  50. angr/analyses/variable_recovery/engine_base.py +11 -0
  51. angr/angrdb/models.py +1 -2
  52. angr/engines/light/engine.py +12 -0
  53. angr/engines/vex/heavy/heavy.py +2 -0
  54. angr/exploration_techniques/spiller_db.py +1 -2
  55. angr/knowledge_plugins/__init__.py +2 -0
  56. angr/knowledge_plugins/decompilation.py +45 -0
  57. angr/knowledge_plugins/functions/function.py +4 -0
  58. angr/knowledge_plugins/functions/function_manager.py +18 -9
  59. angr/knowledge_plugins/functions/function_parser.py +1 -1
  60. angr/knowledge_plugins/functions/soot_function.py +1 -0
  61. angr/knowledge_plugins/key_definitions/atoms.py +8 -0
  62. angr/lib/angr_native.dll +0 -0
  63. angr/misc/ux.py +2 -2
  64. angr/procedures/definitions/parse_win32json.py +2 -1
  65. angr/project.py +17 -1
  66. angr/state_plugins/history.py +6 -4
  67. angr/storage/memory_mixins/actions_mixin.py +7 -7
  68. angr/storage/memory_mixins/address_concretization_mixin.py +5 -5
  69. angr/storage/memory_mixins/bvv_conversion_mixin.py +1 -1
  70. angr/storage/memory_mixins/clouseau_mixin.py +3 -3
  71. angr/storage/memory_mixins/conditional_store_mixin.py +3 -3
  72. angr/storage/memory_mixins/default_filler_mixin.py +3 -3
  73. angr/storage/memory_mixins/memory_mixin.py +45 -34
  74. angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +15 -14
  75. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +27 -16
  76. angr/storage/memory_mixins/paged_memory/pages/cooperation.py +18 -9
  77. angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +5 -5
  78. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +89 -55
  79. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +16 -25
  80. angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +11 -9
  81. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +23 -7
  82. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +1 -1
  83. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +9 -7
  84. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +9 -9
  85. angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +1 -0
  86. angr/storage/memory_mixins/simple_interface_mixin.py +2 -2
  87. angr/storage/memory_mixins/simplification_mixin.py +2 -2
  88. angr/storage/memory_mixins/size_resolution_mixin.py +1 -1
  89. angr/storage/memory_mixins/slotted_memory.py +3 -3
  90. angr/storage/memory_mixins/smart_find_mixin.py +1 -0
  91. angr/storage/memory_mixins/underconstrained_mixin.py +5 -5
  92. angr/storage/memory_mixins/unwrapper_mixin.py +4 -4
  93. angr/storage/memory_object.py +4 -3
  94. angr/utils/bits.py +4 -0
  95. angr/utils/constants.py +1 -1
  96. angr/utils/graph.py +15 -0
  97. angr/utils/tagged_interval_map.py +112 -0
  98. angr/vaults.py +2 -2
  99. {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/METADATA +6 -6
  100. {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/RECORD +104 -97
  101. {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/WHEEL +1 -1
  102. {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/LICENSE +0 -0
  103. {angr-9.2.123.dist-info → angr-9.2.125.dist-info}/entry_points.txt +0 -0
  104. {angr-9.2.123.dist-info → angr-9.2.125.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.123"
5
+ __version__ = "9.2.125"
6
6
 
7
7
  if bytes is str:
8
8
  raise Exception(
angr/analyses/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- # pylint:disable=wrong-import-position
1
+ # " pylint:disable=wrong-import-position
2
2
  from __future__ import annotations
3
3
 
4
4
  from .analysis import Analysis, AnalysesHub
@@ -49,6 +49,10 @@ from .flirt import FlirtAnalysis
49
49
  from .s_propagator import SPropagatorAnalysis
50
50
  from .s_reaching_definitions import SReachingDefinitionsAnalysis
51
51
  from .s_liveness import SLivenessAnalysis
52
+ from .codecave import CodeCaveAnalysis
53
+ from .patchfinder import PatchFinderAnalysis
54
+ from .pathfinder import Pathfinder
55
+ from .smc import SelfModifyingCodeAnalysis
52
56
 
53
57
 
54
58
  __all__ = (
@@ -101,4 +105,8 @@ __all__ = (
101
105
  "SPropagatorAnalysis",
102
106
  "SReachingDefinitionsAnalysis",
103
107
  "SLivenessAnalysis",
108
+ "CodeCaveAnalysis",
109
+ "PatchFinderAnalysis",
110
+ "Pathfinder",
111
+ "SelfModifyingCodeAnalysis",
104
112
  )
@@ -153,6 +153,11 @@ class MipsElfFastResolver(IndirectJumpResolver):
153
153
 
154
154
  def _resolve_case_1(self, addr: int, block: pyvex.IRSB, func_addr: int, gp_value: int, cfg) -> int | None:
155
155
  # lift the block again with the correct setting
156
+
157
+ inital_regs = [(self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr)]
158
+ if gp_value is not None:
159
+ inital_regs.append((self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value))
160
+
156
161
  first_irsb = self.project.factory.block(
157
162
  addr,
158
163
  size=block.size,
@@ -160,10 +165,7 @@ class MipsElfFastResolver(IndirectJumpResolver):
160
165
  const_prop=True,
161
166
  cross_insn_opt=False,
162
167
  load_from_ro_regions=True,
163
- initial_regs=[
164
- (self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr),
165
- (self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value),
166
- ],
168
+ initial_regs=inital_regs,
167
169
  ).vex_nostmt
168
170
 
169
171
  if not isinstance(first_irsb.next, pyvex.IRExpr.RdTmp):
@@ -193,6 +195,10 @@ class MipsElfFastResolver(IndirectJumpResolver):
193
195
  # the register (t9) is set in this block - we can resolve the jump target using only the current block
194
196
  return Case2Result.RESUME, None
195
197
 
198
+ inital_regs = [(self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr)]
199
+ if gp_value is not None:
200
+ inital_regs.append((self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value))
201
+
196
202
  # lift the first block again with the correct setting
197
203
  first_irsb = self.project.factory.block(
198
204
  first_block_addr,
@@ -200,10 +206,7 @@ class MipsElfFastResolver(IndirectJumpResolver):
200
206
  collect_data_refs=False,
201
207
  const_prop=True,
202
208
  load_from_ro_regions=True,
203
- initial_regs=[
204
- (self.project.arch.registers["t9"][0], self.project.arch.registers["t9"][1], func_addr),
205
- (self.project.arch.registers["gp"][0], self.project.arch.registers["gp"][1], gp_value),
206
- ],
209
+ initial_regs=inital_regs,
207
210
  ).vex_nostmt
208
211
 
209
212
  last_reg_setting_tmp = self._get_last_reg_setting_tmp(first_irsb, jump_target_reg)
@@ -51,11 +51,11 @@ class MipsElfGotResolver(IndirectJumpResolver):
51
51
  return False, []
52
52
  dynsym_addr = self._find_and_cache_section_addr(obj, ".dynsym")
53
53
  if dynsym_addr is None:
54
- return None
54
+ return False, []
55
55
 
56
56
  dynstr_addr = self._find_and_cache_section_addr(obj, ".dynstr")
57
57
  if dynstr_addr is None:
58
- return None
58
+ return False, []
59
59
 
60
60
  if block.size != 16:
61
61
  return False, []
@@ -0,0 +1,77 @@
1
+ from __future__ import annotations
2
+ import logging
3
+ from enum import Enum, auto
4
+ from typing import TYPE_CHECKING
5
+ from dataclasses import dataclass
6
+
7
+ from angr.analyses import Analysis, AnalysesHub
8
+
9
+
10
+ if TYPE_CHECKING:
11
+ from angr.knowledge_plugins import Function
12
+
13
+
14
+ log = logging.getLogger(__name__)
15
+
16
+
17
+ class CodeCaveClassification(Enum):
18
+ """
19
+ Type of code caves.
20
+ """
21
+
22
+ ALIGNMENT = auto()
23
+ UNREACHABLE = auto()
24
+
25
+
26
+ @dataclass
27
+ class CodeCave:
28
+ """
29
+ Describes a code cave in a binary.
30
+ """
31
+
32
+ func: Function | None
33
+ addr: int
34
+ size: int
35
+ classification: CodeCaveClassification
36
+
37
+
38
+ class CodeCaveAnalysis(Analysis):
39
+ """
40
+ Best-effort static location of potential vacant code caves for possible code injection:
41
+ - Padding functions
42
+ - Unreachable code
43
+ """
44
+
45
+ codecaves: list[CodeCave]
46
+
47
+ def __init__(self):
48
+ self.codecaves = []
49
+
50
+ if len(self.project.kb.functions) == 0 and self.project.kb.cfgs.get_most_accurate() is None:
51
+ log.warning("Please run CFGFast analysis first, to identify functions")
52
+ return
53
+
54
+ # Alignment functions
55
+ for func in self.project.kb.functions.values():
56
+ if func.is_alignment:
57
+ for block in func.blocks:
58
+ self.codecaves.append(CodeCave(func, block.addr, block.size, CodeCaveClassification.ALIGNMENT))
59
+
60
+ # Unreachable code
61
+ for func in self.project.kb.functions.values():
62
+ if func.is_alignment or func.is_plt or func.is_simprocedure or func.addr in self.project.kb.labels:
63
+ continue
64
+
65
+ in_degree = self.project.kb.callgraph.in_degree(func.addr)
66
+ if in_degree == 0 or (
67
+ in_degree == 1
68
+ and self.project.kb.functions[next(self.project.kb.callgraph.predecessors(func.addr))].is_alignment
69
+ ):
70
+ for block in func.blocks:
71
+ self.codecaves.append(CodeCave(func, block.addr, block.size, CodeCaveClassification.UNREACHABLE))
72
+
73
+ # FIXME: find dead blocks with argument propagation
74
+ # FIXME: find dead blocks with external coverage info
75
+
76
+
77
+ AnalysesHub.register_default("CodeCaves", CodeCaveAnalysis)
@@ -1316,18 +1316,7 @@ class AILSimplifier(Analysis):
1316
1316
  continue
1317
1317
  uses = rd.get_vvar_uses(def_.atom)
1318
1318
 
1319
- elif def_.atom.was_reg:
1320
- uses = rd.get_vvar_uses(def_.atom)
1321
- if (
1322
- def_.atom.reg_offset in self.project.arch.artificial_registers_offsets
1323
- and len(uses) == 1
1324
- and next(iter(uses)) == def_.codeloc
1325
- ):
1326
- # TODO: Verify if we still need this hack after moving to SSA
1327
- # cc_ndep = amd64g_calculate_condition(..., cc_ndep)
1328
- uses = set()
1329
-
1330
- elif def_.atom.was_parameter:
1319
+ elif def_.atom.was_reg or def_.atom.was_parameter:
1331
1320
  uses = rd.get_vvar_uses(def_.atom)
1332
1321
 
1333
1322
  else:
@@ -1425,9 +1414,17 @@ class AILSimplifier(Analysis):
1425
1414
  simplified = True
1426
1415
  continue
1427
1416
  if isinstance(stmt, Assignment) and isinstance(stmt.dst, VirtualVariable):
1428
- # no one is using the returned virtual variable. replace this assignment statement with
1429
- # a call statement
1430
- stmt = stmt.src
1417
+ # no one is using the returned virtual variable.
1418
+ # now the things are a bit tricky here
1419
+ if isinstance(stmt.src, Call):
1420
+ # replace this assignment statement with a call statement
1421
+ stmt = stmt.src
1422
+ elif isinstance(stmt.src, Convert) and isinstance(stmt.src.operand, Call):
1423
+ # the convert is useless now
1424
+ stmt = stmt.src.operand
1425
+ else:
1426
+ # we can't change this stmt at all because it has an expression with Calls inside
1427
+ pass
1431
1428
  else:
1432
1429
  # no calls. remove it
1433
1430
  simplified = True
@@ -1460,7 +1457,7 @@ class AILSimplifier(Analysis):
1460
1457
  def _find_cyclic_dependent_phis_and_dirty_vvars(self, rd: SRDAModel) -> set[int]:
1461
1458
  blocks_dict = {(bb.addr, bb.idx): bb for bb in self.func_graph}
1462
1459
 
1463
- # find dirty vvars
1460
+ # find dirty vvars and vexccall vvars
1464
1461
  dirty_vvar_ids = set()
1465
1462
  for bb in self.func_graph:
1466
1463
  for stmt in bb.statements:
@@ -1468,7 +1465,7 @@ class AILSimplifier(Analysis):
1468
1465
  isinstance(stmt, Assignment)
1469
1466
  and isinstance(stmt.dst, VirtualVariable)
1470
1467
  and stmt.dst.was_reg
1471
- and isinstance(stmt.src, DirtyExpression)
1468
+ and isinstance(stmt.src, (DirtyExpression, VEXCCallExpression))
1472
1469
  ):
1473
1470
  dirty_vvar_ids.add(stmt.dst.varid)
1474
1471
 
@@ -1544,8 +1541,8 @@ class AILSimplifier(Analysis):
1544
1541
  v = False
1545
1542
 
1546
1543
  def _handle_expr(expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement, block) -> Expression | None:
1547
- if isinstance(expr, DirtyExpression) and isinstance(expr.dirty_expr, VEXCCallExpression):
1548
- rewriter = rewriter_cls(expr.dirty_expr, self.project.arch)
1544
+ if isinstance(expr, VEXCCallExpression):
1545
+ rewriter = rewriter_cls(expr, self.project.arch)
1549
1546
  if rewriter.result is not None:
1550
1547
  _any_update.v = True
1551
1548
  return rewriter.result
@@ -143,7 +143,7 @@ class CallSiteMaker(Analysis):
143
143
  if isinstance(arg_loc, SimRegArg):
144
144
  size = arg_loc.size
145
145
  offset = arg_loc.check_offset(cc.arch)
146
- value_and_def = self._resolve_register_argument(call_stmt, arg_loc)
146
+ value_and_def = self._resolve_register_argument(arg_loc)
147
147
  if value_and_def is not None:
148
148
  vvar_def = value_and_def[1]
149
149
  arg_vvars.append(vvar_def)
@@ -283,14 +283,15 @@ class CallSiteMaker(Analysis):
283
283
  l.warning("TODO: Unsupported statement type %s for definitions.", type(stmt))
284
284
  return None
285
285
 
286
- def _resolve_register_argument(self, call_stmt, arg_loc) -> tuple[int | None, Expr.VirtualVariable] | None:
286
+ def _resolve_register_argument(self, arg_loc) -> tuple[int | None, Expr.VirtualVariable] | None:
287
287
  offset = arg_loc.check_offset(self.project.arch)
288
288
 
289
289
  if self._reaching_definitions is not None:
290
290
  # Find its definition
291
- ins_addr = call_stmt.tags["ins_addr"]
292
291
  view = SRDAView(self._reaching_definitions.model)
293
- vvar = view.get_reg_vvar_by_insn(offset, ins_addr, OP_BEFORE, block_idx=self.block.idx)
292
+ vvar = view.get_reg_vvar_by_stmt(
293
+ offset, self.block.addr, self.block.idx, len(self.block.statements) - 1, OP_BEFORE
294
+ )
294
295
 
295
296
  if vvar is not None:
296
297
  vvar_value = view.get_vvar_value(vvar)
@@ -318,8 +319,8 @@ class CallSiteMaker(Analysis):
318
319
  if self._reaching_definitions is not None:
319
320
  # find its definition
320
321
  view = SRDAView(self._reaching_definitions.model)
321
- vvar = view.get_stack_vvar_by_insn(
322
- sp_offset, size, call_stmt.ins_addr, OP_BEFORE, block_idx=self.block.idx
322
+ vvar = view.get_stack_vvar_by_stmt(
323
+ sp_offset, size, self.block.addr, self.block.idx, len(self.block.statements) - 1, OP_BEFORE
323
324
  )
324
325
  if vvar is not None:
325
326
  value = view.get_vvar_value(vvar)
@@ -416,7 +417,7 @@ class CallSiteMaker(Analysis):
416
417
 
417
418
  value = None
418
419
  if isinstance(arg_loc, SimRegArg):
419
- value_and_def = self._resolve_register_argument(call_stmt, arg_loc)
420
+ value_and_def = self._resolve_register_argument(arg_loc)
420
421
  if value_and_def is not None:
421
422
  value = value_and_def[0]
422
423
 
@@ -20,7 +20,7 @@ class AMD64CCallRewriter(CCallRewriterBase):
20
20
  __slots__ = ()
21
21
 
22
22
  def _rewrite(self, ccall: Expr.VEXCCallExpression) -> Expr.Expression | None:
23
- if ccall.cee_name == "amd64g_calculate_condition":
23
+ if ccall.callee == "amd64g_calculate_condition":
24
24
  cond = ccall.operands[0]
25
25
  op = ccall.operands[1]
26
26
  dep_1 = ccall.operands[2]
@@ -288,6 +288,28 @@ class AMD64CCallRewriter(CCallRewriterBase):
288
288
 
289
289
  r = Expr.BinaryOp(ccall.idx, "CmpLT", (dep_1, dep_2), True, **ccall.tags)
290
290
  return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
291
+
292
+ if op_v in {
293
+ AMD64_OpTypes["G_CC_OP_LOGICB"],
294
+ AMD64_OpTypes["G_CC_OP_LOGICW"],
295
+ AMD64_OpTypes["G_CC_OP_LOGICL"],
296
+ AMD64_OpTypes["G_CC_OP_LOGICQ"],
297
+ }:
298
+ # dep_1 is the result, dep_2 is always zero
299
+ # dep_1 <s 0
300
+
301
+ dep_1 = self._fix_size(
302
+ dep_1,
303
+ op_v,
304
+ AMD64_OpTypes["G_CC_OP_LOGICB"],
305
+ AMD64_OpTypes["G_CC_OP_LOGICW"],
306
+ AMD64_OpTypes["G_CC_OP_LOGICL"],
307
+ ccall.tags,
308
+ )
309
+ zero = Expr.Const(None, None, 0, dep_1.bits)
310
+ r = Expr.BinaryOp(ccall.idx, "CmpLT", (dep_1, zero), True, **ccall.tags)
311
+ return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
312
+
291
313
  elif cond_v == AMD64_CondTypes["CondNBE"]:
292
314
  if op_v in {
293
315
  AMD64_OpTypes["G_CC_OP_SUBB"],
@@ -390,7 +412,7 @@ class AMD64CCallRewriter(CCallRewriterBase):
390
412
  )
391
413
  return Expr.Convert(None, r.bits, ccall.bits, False, r, **ccall.tags)
392
414
 
393
- elif ccall.cee_name == "amd64g_calculate_rflags_c":
415
+ elif ccall.callee == "amd64g_calculate_rflags_c":
394
416
  # calculate the carry flag
395
417
  op = ccall.operands[0]
396
418
  dep_1 = ccall.operands[1]
@@ -42,6 +42,7 @@ from .optimization_passes import (
42
42
  OptimizationPassStage,
43
43
  RegisterSaveAreaSimplifier,
44
44
  StackCanarySimplifier,
45
+ TagSlicer,
45
46
  DUPLICATING_OPTS,
46
47
  CONDENSING_OPTS,
47
48
  )
@@ -110,6 +111,8 @@ class Clinic(Analysis):
110
111
  inlined_counts: dict[int, int] | None = None,
111
112
  inlining_parents: set[int] | None = None,
112
113
  vvar_id_start: int = 0,
114
+ optimization_scratch: dict[str, Any] | None = None,
115
+ desired_variables: set[str] | None = None,
113
116
  ):
114
117
  if not func.normalized and mode == ClinicMode.DECOMPILE:
115
118
  raise ValueError("Decompilation must work on normalized function graphs.")
@@ -124,6 +127,7 @@ class Clinic(Analysis):
124
127
  self.variable_kb = variable_kb
125
128
  self.externs: set[SimMemoryVariable] = set()
126
129
  self.data_refs: dict[int, int] = {} # data address to instruction address
130
+ self.optimization_scratch = optimization_scratch if optimization_scratch is not None else {}
127
131
 
128
132
  self._func_graph: networkx.DiGraph | None = None
129
133
  self._ail_manager = None
@@ -152,6 +156,7 @@ class Clinic(Analysis):
152
156
  self._inline_functions = inline_functions
153
157
  self._inlined_counts = {} if inlined_counts is None else inlined_counts
154
158
  self._inlining_parents = inlining_parents or ()
159
+ self._desired_variables = desired_variables
155
160
 
156
161
  self._register_save_areas_removed: bool = False
157
162
 
@@ -218,6 +223,9 @@ class Clinic(Analysis):
218
223
  ail_graph = self._inline_child_functions(ail_graph)
219
224
 
220
225
  ail_graph = self._decompilation_simplifications(ail_graph)
226
+
227
+ if self._desired_variables:
228
+ ail_graph = self._slice_variables(ail_graph)
221
229
  self.graph = ail_graph
222
230
 
223
231
  def _decompilation_graph_recovery(self):
@@ -277,6 +285,27 @@ class Clinic(Analysis):
277
285
 
278
286
  return ail_graph
279
287
 
288
+ def _slice_variables(self, ail_graph):
289
+ nodes_index = {(n.addr, n.idx): n for n in ail_graph.nodes()}
290
+
291
+ vfm = self.variable_kb.variables.function_managers[self.function.addr]
292
+ for v_name in self._desired_variables:
293
+ v = next(iter(vv for vv in vfm._unified_variables if vv.name == v_name))
294
+ for va in vfm.get_variable_accesses(v):
295
+ nodes_index[(va.location.block_addr, va.location.block_idx)].statements[va.location.stmt_idx].tags[
296
+ "keep_in_slice"
297
+ ] = True
298
+
299
+ a = TagSlicer(
300
+ self.function,
301
+ graph=ail_graph,
302
+ variable_kb=self.variable_kb,
303
+ )
304
+ if a.out_graph:
305
+ # use the new graph
306
+ ail_graph = a.out_graph
307
+ return ail_graph
308
+
280
309
  def _inline_child_functions(self, ail_graph):
281
310
  for blk in ail_graph.nodes():
282
311
  for idx, stmt in enumerate(blk.statements):
@@ -907,22 +936,31 @@ class Clinic(Analysis):
907
936
  Convert a VEX block to an AIL block.
908
937
 
909
938
  :param block_node: A BlockNode instance.
910
- :return: An converted AIL block.
939
+ :return: A converted AIL block.
911
940
  :rtype: ailment.Block
912
941
  """
913
942
 
914
943
  if type(block_node) is not BlockNode:
915
944
  return block_node
916
945
 
946
+ if block_node.size == 0:
947
+ return ailment.Block(block_node.addr, 0, statements=[])
948
+
917
949
  block = self.project.factory.block(block_node.addr, block_node.size, cross_insn_opt=False)
918
950
  if block.vex.jumpkind not in {"Ijk_Call", "Ijk_Boring", "Ijk_Ret"} and not block.vex.jumpkind.startswith(
919
951
  "Ijk_Sys"
920
952
  ):
921
953
  # we don't support lifting this block. use a dummy block instead
954
+ dirty_expr = ailment.Expr.DirtyExpression(
955
+ self._ail_manager.next_atom,
956
+ f"Unsupported jumpkind {block.vex.jumpkind} at address {block_node.addr}",
957
+ [],
958
+ bits=0,
959
+ )
922
960
  statements = [
923
961
  ailment.Stmt.DirtyStatement(
924
962
  self._ail_manager.next_atom(),
925
- f"Unsupported jumpkind {block.vex.jumpkind} at address {block_node.addr}",
963
+ dirty_expr,
926
964
  ins_addr=block_node.addr,
927
965
  )
928
966
  ]
@@ -1219,6 +1257,7 @@ class Clinic(Analysis):
1219
1257
  variable_kb=variable_kb,
1220
1258
  vvar_id_start=self.vvar_id_start,
1221
1259
  entry_node_addr=self.entry_node_addr,
1260
+ scratch=self.optimization_scratch,
1222
1261
  **kwargs,
1223
1262
  )
1224
1263
  if a.out_graph:
@@ -1256,6 +1295,7 @@ class Clinic(Analysis):
1256
1295
  ailment.Expr.VirtualVariableCategory.PARAMETER,
1257
1296
  oident=arg.reg,
1258
1297
  ins_addr=self.function.addr,
1298
+ vex_block_addr=self.function.addr,
1259
1299
  )
1260
1300
  self.vvar_id_start += 1
1261
1301
  arg_vvars[arg_vvar.varid] = arg_vvar, arg
@@ -1269,6 +1309,7 @@ class Clinic(Analysis):
1269
1309
  False,
1270
1310
  arg_vvar,
1271
1311
  ins_addr=self.function.addr,
1312
+ vex_block_addr=self.function.addr,
1272
1313
  )
1273
1314
 
1274
1315
  fullreg_dst = ailment.Expr.Register(
@@ -1277,12 +1318,14 @@ class Clinic(Analysis):
1277
1318
  basereg_offset,
1278
1319
  basereg_size * self.project.arch.byte_width,
1279
1320
  ins_addr=self.function.addr,
1321
+ vex_block_addr=self.function.addr,
1280
1322
  )
1281
1323
  stmt = ailment.Stmt.Assignment(
1282
1324
  self._ail_manager.next_atom(),
1283
1325
  fullreg_dst,
1284
1326
  arg_vvar,
1285
1327
  ins_addr=self.function.addr,
1328
+ vex_block_addr=self.function.addr,
1286
1329
  )
1287
1330
  new_stmts.append(stmt)
1288
1331
 
@@ -1313,6 +1356,7 @@ class Clinic(Analysis):
1313
1356
  ail_graph,
1314
1357
  entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
1315
1358
  ail_manager=self._ail_manager,
1359
+ ssa_tmps=True,
1316
1360
  ssa_stackvars=True,
1317
1361
  vvar_id_start=self.vvar_id_start,
1318
1362
  )
@@ -1792,6 +1836,18 @@ class Clinic(Analysis):
1792
1836
  elif isinstance(expr, ailment.Stmt.Call):
1793
1837
  self._link_variables_on_call(variable_manager, global_variables, block, stmt_idx, expr, is_expr=True)
1794
1838
 
1839
+ elif isinstance(expr, ailment.Expr.VEXCCallExpression):
1840
+ for operand in expr.operands:
1841
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, operand)
1842
+
1843
+ elif isinstance(expr, ailment.Expr.DirtyExpression):
1844
+ for operand in expr.operands:
1845
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, operand)
1846
+ if expr.maddr:
1847
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.maddr)
1848
+ if expr.guard:
1849
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.guard)
1850
+
1795
1851
  def _function_graph_to_ail_graph(self, func_graph, blocks_by_addr_and_size=None):
1796
1852
  if blocks_by_addr_and_size is None:
1797
1853
  blocks_by_addr_and_size = self._blocks_by_addr_and_size
@@ -160,6 +160,8 @@ _ail2claripy_op_mapping = {
160
160
  "GetMSBs": lambda expr, _, m: _dummy_bvs(expr, m),
161
161
  "InterleaveLOV": lambda expr, _, m: _dummy_bvs(expr, m),
162
162
  "InterleaveHIV": lambda expr, _, m: _dummy_bvs(expr, m),
163
+ # catch-all
164
+ "_DUMMY_": lambda expr, _, m: _dummy_bvs(expr, m),
163
165
  }
164
166
 
165
167
  #
@@ -771,7 +773,7 @@ class ConditionProcessor:
771
773
 
772
774
  if isinstance(
773
775
  condition,
774
- (ailment.Expr.DirtyExpression, ailment.Expr.BasePointerOffset, ailment.Expr.ITE),
776
+ (ailment.Expr.VEXCCallExpression, ailment.Expr.BasePointerOffset, ailment.Expr.ITE),
775
777
  ):
776
778
  return _dummy_bvs(condition, self._condition_mapping)
777
779
  if isinstance(condition, ailment.Stmt.Call):
@@ -828,9 +830,14 @@ class ConditionProcessor:
828
830
  # fall back to op
829
831
  lambda_expr = _ail2claripy_op_mapping.get(condition.op, None)
830
832
  if lambda_expr is None:
831
- raise NotImplementedError(
832
- f"Unsupported AIL expression operation {condition.op} or {condition.verbose_op}. Consider implementing."
833
+ # fall back to the catch-all option
834
+ l.debug(
835
+ "Unsupported AIL expression operation %s (or verbose: %s). Fall back to the default catch-all dummy "
836
+ "option. Consider implementing.",
837
+ condition.op,
838
+ condition.verbose_op,
833
839
  )
840
+ lambda_expr = _ail2claripy_op_mapping["_DUMMY_"]
834
841
  r = lambda_expr(condition, self.claripy_ast_from_ail_condition, self._condition_mapping)
835
842
 
836
843
  if isinstance(r, claripy.ast.Bool) and nobool:
@@ -14,6 +14,7 @@ class DecompilationCache:
14
14
  """
15
15
 
16
16
  __slots__ = (
17
+ "parameters",
17
18
  "addr",
18
19
  "type_constraints",
19
20
  "func_typevar",
@@ -25,6 +26,7 @@ class DecompilationCache:
25
26
  )
26
27
 
27
28
  def __init__(self, addr):
29
+ self.parameters: dict[str, Any] = {}
28
30
  self.addr = addr
29
31
  self.type_constraints: set | None = None
30
32
  self.func_typevar = None