angr 9.2.135__py3-none-manylinux2014_x86_64.whl → 9.2.137__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 (198) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/__init__.py +3 -7
  3. angr/analyses/analysis.py +4 -0
  4. angr/analyses/backward_slice.py +1 -2
  5. angr/analyses/binary_optimizer.py +3 -4
  6. angr/analyses/bindiff.py +4 -6
  7. angr/analyses/boyscout.py +1 -3
  8. angr/analyses/callee_cleanup_finder.py +4 -4
  9. angr/analyses/calling_convention/calling_convention.py +6 -4
  10. angr/analyses/calling_convention/fact_collector.py +10 -3
  11. angr/analyses/cdg.py +1 -2
  12. angr/analyses/cfg/cfb.py +1 -3
  13. angr/analyses/cfg/cfg.py +2 -2
  14. angr/analyses/cfg/cfg_base.py +40 -68
  15. angr/analyses/cfg/cfg_emulated.py +1 -104
  16. angr/analyses/cfg/cfg_fast.py +90 -27
  17. angr/analyses/cfg/cfg_fast_soot.py +1 -1
  18. angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
  19. angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +46 -10
  20. angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +5 -1
  21. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +65 -14
  22. angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
  23. angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +24 -5
  24. angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +2 -5
  25. angr/analyses/class_identifier.py +1 -2
  26. angr/analyses/complete_calling_conventions.py +3 -0
  27. angr/analyses/congruency_check.py +2 -3
  28. angr/analyses/data_dep/data_dependency_analysis.py +2 -2
  29. angr/analyses/ddg.py +1 -4
  30. angr/analyses/decompiler/ail_simplifier.py +15 -5
  31. angr/analyses/decompiler/block_simplifier.py +2 -2
  32. angr/analyses/decompiler/ccall_rewriters/__init__.py +2 -0
  33. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
  34. angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +69 -0
  35. angr/analyses/decompiler/clinic.py +119 -72
  36. angr/analyses/decompiler/condition_processor.py +2 -0
  37. angr/analyses/decompiler/decompiler.py +1 -0
  38. angr/analyses/decompiler/dephication/dephication_base.py +2 -0
  39. angr/analyses/decompiler/dephication/rewriting_engine.py +8 -6
  40. angr/analyses/decompiler/dephication/seqnode_dephication.py +10 -1
  41. angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
  42. angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +2 -2
  43. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +1 -1
  44. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
  45. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +1 -2
  46. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +1 -1
  47. angr/analyses/decompiler/sequence_walker.py +6 -2
  48. angr/analyses/decompiler/ssailification/rewriting.py +11 -1
  49. angr/analyses/decompiler/ssailification/rewriting_engine.py +56 -19
  50. angr/analyses/decompiler/ssailification/ssailification.py +13 -3
  51. angr/analyses/decompiler/ssailification/traversal.py +28 -2
  52. angr/analyses/decompiler/ssailification/traversal_state.py +6 -1
  53. angr/analyses/decompiler/structured_codegen/c.py +44 -21
  54. angr/analyses/decompiler/structuring/phoenix.py +118 -15
  55. angr/analyses/decompiler/utils.py +113 -8
  56. angr/analyses/disassembly.py +5 -5
  57. angr/analyses/fcp/__init__.py +4 -0
  58. angr/analyses/fcp/fcp.py +429 -0
  59. angr/analyses/identifier/identify.py +1 -3
  60. angr/analyses/loopfinder.py +4 -3
  61. angr/analyses/patchfinder.py +1 -1
  62. angr/analyses/propagator/engine_base.py +4 -3
  63. angr/analyses/propagator/propagator.py +14 -53
  64. angr/analyses/reaching_definitions/function_handler.py +1 -1
  65. angr/analyses/reassembler.py +1 -2
  66. angr/analyses/s_liveness.py +5 -1
  67. angr/analyses/s_propagator.py +26 -7
  68. angr/analyses/s_reaching_definitions/s_rda_model.py +2 -1
  69. angr/analyses/s_reaching_definitions/s_rda_view.py +20 -1
  70. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +11 -1
  71. angr/analyses/soot_class_hierarchy.py +1 -2
  72. angr/analyses/stack_pointer_tracker.py +29 -3
  73. angr/analyses/static_hooker.py +1 -2
  74. angr/analyses/typehoon/simple_solver.py +2 -2
  75. angr/analyses/variable_recovery/engine_ail.py +19 -7
  76. angr/analyses/variable_recovery/engine_base.py +16 -14
  77. angr/analyses/variable_recovery/engine_vex.py +2 -2
  78. angr/analyses/variable_recovery/variable_recovery_fast.py +23 -3
  79. angr/analyses/veritesting.py +4 -7
  80. angr/analyses/vfg.py +1 -1
  81. angr/analyses/vsa_ddg.py +1 -2
  82. angr/block.py +62 -22
  83. angr/callable.py +1 -3
  84. angr/calling_conventions.py +3 -3
  85. angr/codenode.py +5 -1
  86. angr/concretization_strategies/__init__.py +1 -83
  87. angr/concretization_strategies/any.py +2 -1
  88. angr/concretization_strategies/any_named.py +1 -1
  89. angr/concretization_strategies/base.py +81 -0
  90. angr/concretization_strategies/controlled_data.py +2 -1
  91. angr/concretization_strategies/eval.py +2 -1
  92. angr/concretization_strategies/logging.py +3 -1
  93. angr/concretization_strategies/max.py +2 -1
  94. angr/concretization_strategies/nonzero.py +2 -1
  95. angr/concretization_strategies/nonzero_range.py +2 -1
  96. angr/concretization_strategies/norepeats.py +2 -1
  97. angr/concretization_strategies/norepeats_range.py +2 -1
  98. angr/concretization_strategies/range.py +2 -1
  99. angr/concretization_strategies/signed_add.py +2 -1
  100. angr/concretization_strategies/single.py +2 -1
  101. angr/concretization_strategies/solutions.py +2 -1
  102. angr/concretization_strategies/unlimited_range.py +2 -1
  103. angr/engines/__init__.py +8 -5
  104. angr/engines/engine.py +3 -5
  105. angr/engines/failure.py +4 -5
  106. angr/engines/pcode/emulate.py +1 -1
  107. angr/engines/pcode/lifter.py +31 -18
  108. angr/engines/procedure.py +5 -7
  109. angr/engines/soot/expressions/__init__.py +20 -23
  110. angr/engines/soot/expressions/base.py +4 -4
  111. angr/engines/soot/expressions/invoke.py +1 -2
  112. angr/engines/soot/statements/__init__.py +10 -12
  113. angr/engines/soot/values/__init__.py +10 -12
  114. angr/engines/soot/values/arrayref.py +3 -3
  115. angr/engines/soot/values/instancefieldref.py +3 -2
  116. angr/engines/successors.py +18 -12
  117. angr/engines/syscall.py +4 -6
  118. angr/engines/unicorn.py +3 -2
  119. angr/engines/vex/claripy/ccall.py +8 -10
  120. angr/engines/vex/claripy/datalayer.py +4 -5
  121. angr/engines/vex/lifter.py +9 -6
  122. angr/exploration_techniques/__init__.py +0 -2
  123. angr/exploration_techniques/spiller.py +1 -3
  124. angr/exploration_techniques/stochastic.py +2 -3
  125. angr/factory.py +3 -9
  126. angr/flirt/build_sig.py +8 -15
  127. angr/knowledge_plugins/cfg/cfg_model.py +20 -17
  128. angr/knowledge_plugins/functions/function.py +70 -79
  129. angr/knowledge_plugins/functions/function_manager.py +8 -7
  130. angr/knowledge_plugins/functions/function_parser.py +1 -1
  131. angr/knowledge_plugins/functions/soot_function.py +21 -24
  132. angr/knowledge_plugins/propagations/propagation_model.py +4 -5
  133. angr/knowledge_plugins/propagations/states.py +0 -511
  134. angr/knowledge_plugins/variables/variable_manager.py +16 -10
  135. angr/procedures/libc/memcpy.py +4 -4
  136. angr/procedures/procedure_dict.py +3 -2
  137. angr/protos/__init__.py +2 -5
  138. angr/protos/cfg_pb2.py +21 -18
  139. angr/protos/function_pb2.py +17 -14
  140. angr/protos/primitives_pb2.py +44 -39
  141. angr/protos/variables_pb2.py +36 -31
  142. angr/protos/xrefs_pb2.py +15 -12
  143. angr/sim_procedure.py +15 -16
  144. angr/sim_variable.py +13 -1
  145. angr/simos/__init__.py +2 -0
  146. angr/simos/javavm.py +4 -6
  147. angr/simos/xbox.py +32 -0
  148. angr/state_plugins/__init__.py +0 -2
  149. angr/state_plugins/callstack.py +4 -4
  150. angr/state_plugins/cgc.py +3 -2
  151. angr/state_plugins/gdb.py +6 -5
  152. angr/state_plugins/globals.py +1 -2
  153. angr/state_plugins/heap/heap_brk.py +1 -2
  154. angr/state_plugins/history.py +10 -12
  155. angr/state_plugins/inspect.py +3 -5
  156. angr/state_plugins/libc.py +2 -2
  157. angr/state_plugins/log.py +8 -10
  158. angr/state_plugins/loop_data.py +1 -2
  159. angr/state_plugins/posix.py +7 -7
  160. angr/state_plugins/preconstrainer.py +2 -3
  161. angr/state_plugins/scratch.py +5 -8
  162. angr/state_plugins/sim_action.py +3 -3
  163. angr/state_plugins/solver.py +8 -3
  164. angr/state_plugins/symbolizer.py +5 -4
  165. angr/state_plugins/uc_manager.py +3 -3
  166. angr/state_plugins/unicorn_engine.py +5 -1
  167. angr/state_plugins/view.py +3 -5
  168. angr/storage/file.py +3 -5
  169. angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
  170. angr/storage/memory_mixins/bvv_conversion_mixin.py +3 -3
  171. angr/storage/memory_mixins/clouseau_mixin.py +1 -3
  172. angr/storage/memory_mixins/name_resolution_mixin.py +1 -3
  173. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +13 -15
  174. angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -22
  175. angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
  176. angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
  177. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
  178. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
  179. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +3 -4
  180. angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
  181. angr/storage/memory_mixins/smart_find_mixin.py +1 -1
  182. angr/storage/memory_mixins/underconstrained_mixin.py +1 -1
  183. angr/storage/memory_mixins/unwrapper_mixin.py +1 -3
  184. angr/utils/enums_conv.py +28 -12
  185. angr/utils/segment_list.py +25 -22
  186. angr/utils/timing.py +18 -1
  187. angr/vaults.py +5 -6
  188. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/METADATA +7 -7
  189. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/RECORD +193 -191
  190. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/WHEEL +1 -1
  191. angr/analyses/propagator/outdated_definition_walker.py +0 -159
  192. angr/analyses/propagator/tmpvar_finder.py +0 -18
  193. angr/engines/concrete.py +0 -180
  194. angr/exploration_techniques/symbion.py +0 -80
  195. angr/state_plugins/concrete.py +0 -295
  196. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/LICENSE +0 -0
  197. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/entry_points.txt +0 -0
  198. {angr-9.2.135.dist-info → angr-9.2.137.dist-info}/top_level.txt +0 -0
@@ -263,7 +263,7 @@ class ITERegionConverter(OptimizationPass):
263
263
 
264
264
  # is this the statement that we are looking for?
265
265
  found_true_src_vvar, found_false_src_vvar = False, False
266
- for src, vvar in stmt.src.src_and_vvars:
266
+ for _src, vvar in stmt.src.src_and_vvars:
267
267
  if vvar is not None:
268
268
  if vvar.varid == true_stmt_dst.varid:
269
269
  found_true_src_vvar = True
@@ -557,7 +557,7 @@ class LoweredSwitchSimplifier(StructuringOptimizationPass):
557
557
  varhash_to_caselists[v].append((cases, extra_cmp_nodes))
558
558
 
559
559
  for v, caselists in list(varhash_to_caselists.items()):
560
- for idx, (cases, redundant_nodes) in list(enumerate(caselists)):
560
+ for idx, (cases, _redundant_nodes) in list(enumerate(caselists)):
561
561
  # filter: each case value should only appear once
562
562
  if len({case.value for case in cases}) != len(cases):
563
563
  caselists[idx] = None
@@ -571,8 +571,7 @@ class ReturnDuplicatorBase:
571
571
  new_name = stmt.name if stmt.name else f"Label_{stmt.ins_addr:x}"
572
572
  if stmt.block_idx is not None:
573
573
  suffix = f"__{stmt.block_idx}"
574
- if new_name.endswith(suffix):
575
- new_name = new_name[: -len(suffix)]
574
+ new_name = new_name.removesuffix(suffix)
576
575
  else:
577
576
  new_name = stmt.name
578
577
  new_name += f"__{block.idx}"
@@ -144,7 +144,7 @@ class StackCanarySimplifier(OptimizationPass):
144
144
  nodes_to_process.append((pred, canary_check_stmt_idx, stack_chk_fail_caller, ret_node))
145
145
 
146
146
  # Awesome. Now patch this function.
147
- for pred, canary_check_stmt_idx, stack_chk_fail_caller, ret_node in nodes_to_process:
147
+ for pred, _canary_check_stmt_idx, stack_chk_fail_caller, ret_node in nodes_to_process:
148
148
  # Patch the pred so that it jumps to the one that is not stack_chk_fail_caller
149
149
  pred_copy = pred.copy()
150
150
  pred_copy.statements[-1] = ailment.Stmt.Jump(
@@ -204,13 +204,17 @@ class SequenceWalker:
204
204
 
205
205
  new_false_node = self._handle(node.false_node, parent=node, index=1) if node.false_node is not None else None
206
206
 
207
- if new_true_node is None and new_false_node is None:
207
+ new_condition = (
208
+ self._handle(node.condition, parent=node, label="condition") if node.condition is not None else None
209
+ )
210
+
211
+ if new_true_node is None and new_false_node is None and new_condition is None:
208
212
  return None
209
213
 
210
214
  return ConditionNode(
211
215
  node.addr,
212
216
  node.reaching_condition,
213
- node.condition,
217
+ node.condition if new_condition is None else new_condition,
214
218
  node.true_node if new_true_node is None else new_true_node,
215
219
  false_node=node.false_node if new_false_node is None else new_false_node,
216
220
  )
@@ -40,6 +40,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
40
40
  stackvar_locs: dict[int, int],
41
41
  rewrite_tmps: bool,
42
42
  ail_manager,
43
+ func_args: set[VirtualVariable],
43
44
  vvar_id_start: int = 0,
44
45
  ):
45
46
  self.project = project
@@ -55,6 +56,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
55
56
  self._stackvar_locs = stackvar_locs
56
57
  self._rewrite_tmps = rewrite_tmps
57
58
  self._ail_manager = ail_manager
59
+ self._func_args = func_args
58
60
  self._engine_ail = SimEngineSSARewriting(
59
61
  self.project,
60
62
  sp_tracker=sp_tracker,
@@ -205,12 +207,20 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, NodeType, object, object
205
207
  self.insert_phi_statements(node, phi_stmts)
206
208
 
207
209
  def _initial_abstract_state(self, node) -> RewritingState:
208
- return RewritingState(
210
+ state = RewritingState(
209
211
  CodeLocation(node.addr, stmt_idx=0, ins_addr=node.addr, block_idx=node.idx),
210
212
  self.project.arch,
211
213
  self._function,
212
214
  node,
213
215
  )
216
+ # update state with function arguments
217
+ for func_arg in self._func_args:
218
+ if func_arg.oident[0] == VirtualVariableCategory.REGISTER:
219
+ reg_offset, reg_size = func_arg.oident[1], func_arg.size
220
+ state.registers[reg_offset][reg_size] = func_arg
221
+ elif func_arg.oident[0] == VirtualVariableCategory.STACK:
222
+ state.stackvars[func_arg.oident[1]][func_arg.size] = func_arg
223
+ return state
214
224
 
215
225
  def _run_on_node(self, node, state: RewritingState):
216
226
  """
@@ -462,7 +462,7 @@ class SimEngineSSARewriting(
462
462
  base_mask = Const(self.ail_manager.next_atom(), None, base_mask, existing_vvar.bits)
463
463
  new_base_expr = BinaryOp(
464
464
  self.ail_manager.next_atom(),
465
- "Or",
465
+ "And",
466
466
  [existing_vvar, base_mask],
467
467
  False,
468
468
  bits=existing_vvar.bits,
@@ -618,6 +618,15 @@ class SimEngineSSARewriting(
618
618
  ):
619
619
  vvar = self.state.registers[reg_expr.reg_offset][reg_expr.size]
620
620
  assert vvar is not None
621
+ if vvar.category == VirtualVariableCategory.PARAMETER:
622
+ return VirtualVariable(
623
+ reg_expr.idx,
624
+ vvar.varid,
625
+ vvar.bits,
626
+ VirtualVariableCategory.PARAMETER,
627
+ oident=vvar.oident,
628
+ **vvar.tags,
629
+ )
621
630
  return VirtualVariable(
622
631
  reg_expr.idx,
623
632
  vvar.varid,
@@ -640,6 +649,20 @@ class SimEngineSSARewriting(
640
649
  vvar,
641
650
  **reg_expr.tags,
642
651
  )
652
+ elif reg_expr.size > existing_size:
653
+ # part of the variable exists... maybe it's a parameter?
654
+ vvar = self.state.registers[reg_expr.reg_offset][existing_size]
655
+ if vvar.category == VirtualVariableCategory.PARAMETER:
656
+ # just zero-extend it
657
+ return Convert(
658
+ self.ail_manager.next_atom(),
659
+ existing_size * self.project.arch.byte_width,
660
+ reg_expr.size * self.project.arch.byte_width,
661
+ False,
662
+ vvar,
663
+ **vvar.tags,
664
+ )
665
+ break
643
666
  else:
644
667
  break
645
668
 
@@ -651,24 +674,29 @@ class SimEngineSSARewriting(
651
674
  ins_addr=reg_expr.ins_addr,
652
675
  )
653
676
  # extract
654
- shift_amount = Const(
655
- self.ail_manager.next_atom(),
656
- None,
657
- (reg_expr.reg_offset - vvar.oident) * self.arch.byte_width,
658
- 8,
659
- **reg_expr.tags,
660
- )
661
- shifted = BinaryOp(
662
- self.ail_manager.next_atom(),
663
- "Shr",
664
- [
665
- vvar,
666
- shift_amount,
667
- ],
668
- False,
669
- bits=vvar.bits,
670
- **reg_expr.tags,
671
- )
677
+ if reg_expr.reg_offset == vvar.oident:
678
+ shifted = vvar
679
+ else:
680
+ shift_amount = Const(
681
+ self.ail_manager.next_atom(),
682
+ None,
683
+ (reg_expr.reg_offset - vvar.oident) * self.arch.byte_width,
684
+ 8,
685
+ **reg_expr.tags,
686
+ )
687
+ shifted = BinaryOp(
688
+ self.ail_manager.next_atom(),
689
+ "Shr",
690
+ [
691
+ vvar,
692
+ shift_amount,
693
+ ],
694
+ False,
695
+ bits=vvar.bits,
696
+ **reg_expr.tags,
697
+ )
698
+ if shifted.bits == reg_expr.bits:
699
+ return shifted
672
700
  return Convert(
673
701
  self.ail_manager.next_atom(),
674
702
  shifted.bits,
@@ -700,6 +728,15 @@ class SimEngineSSARewriting(
700
728
  # TODO: Support truncation
701
729
  # TODO: Maybe also support concatenation
702
730
  vvar = self.state.stackvars[expr.addr.offset][expr.size]
731
+ if vvar.category == VirtualVariableCategory.PARAMETER:
732
+ return VirtualVariable(
733
+ expr.idx,
734
+ vvar.varid,
735
+ vvar.bits,
736
+ VirtualVariableCategory.PARAMETER,
737
+ oident=vvar.oident,
738
+ **vvar.tags,
739
+ )
703
740
  return VirtualVariable(
704
741
  expr.idx,
705
742
  vvar.varid,
@@ -5,7 +5,7 @@ from collections import defaultdict
5
5
  from itertools import count
6
6
  from bisect import bisect_left
7
7
 
8
- from ailment.expression import Expression, Register, StackBaseOffset, Tmp
8
+ from ailment.expression import Expression, Register, StackBaseOffset, Tmp, VirtualVariable, VirtualVariableCategory
9
9
  from ailment.statement import Statement, Store
10
10
 
11
11
  from angr.knowledge_plugins.functions import Function
@@ -34,6 +34,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
34
34
  ail_manager=None,
35
35
  ssa_stackvars: bool = False,
36
36
  ssa_tmps: bool = False,
37
+ func_args: set[VirtualVariable] | None = None,
37
38
  vvar_id_start: int = 0,
38
39
  ):
39
40
  """
@@ -53,6 +54,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
53
54
  self._ail_manager = ail_manager
54
55
  self._ssa_stackvars = ssa_stackvars
55
56
  self._ssa_tmps = ssa_tmps
57
+ self._func_args = func_args if func_args is not None else set()
56
58
  self._entry = (
57
59
  entry
58
60
  if entry is not None
@@ -71,6 +73,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
71
73
  bp_as_gpr,
72
74
  ssa_stackvars,
73
75
  ssa_tmps,
76
+ self._func_args,
74
77
  )
75
78
 
76
79
  # calculate virtual variables and phi nodes
@@ -91,6 +94,7 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
91
94
  self._stackvar_locs,
92
95
  self._ssa_tmps,
93
96
  self._ail_manager,
97
+ self._func_args,
94
98
  vvar_id_start=vvar_id_start,
95
99
  )
96
100
  self.out_graph = rewriter.out_graph
@@ -122,6 +126,11 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
122
126
  # for stack variables, we collect all definitions and identify stack variable locations using heuristics
123
127
 
124
128
  stackvar_locs = self._synthesize_stackvar_locs([def_ for def_, _ in def_to_loc if isinstance(def_, Store)])
129
+ # handle function arguments
130
+ if self._func_args:
131
+ for func_arg in self._func_args:
132
+ if func_arg.oident[0] == VirtualVariableCategory.STACK:
133
+ stackvar_locs[func_arg.oident[1]] = func_arg.size
125
134
  sorted_stackvar_offs = sorted(stackvar_locs)
126
135
  else:
127
136
  stackvar_locs = {}
@@ -137,9 +146,10 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
137
146
  udef_to_defs[("reg", base_off, base_reg_bits)].add(def_)
138
147
  udef_to_blockkeys[("reg", base_off, base_reg_bits)].add((loc.block_addr, loc.block_idx))
139
148
  # add a definition for the partial register
140
- if base_off != def_.reg_offset:
149
+ if base_off != def_.reg_offset or base_size != def_.size:
141
150
  reg_bits = def_.size * self.project.arch.byte_width
142
- udef_to_defs[("reg", def_.reg_offset, reg_bits)].add((loc.block_addr, loc.block_idx))
151
+ udef_to_defs[("reg", def_.reg_offset, reg_bits)].add(def_)
152
+ udef_to_blockkeys[("reg", def_.reg_offset, reg_bits)].add((loc.block_addr, loc.block_idx))
143
153
  elif isinstance(def_, Store):
144
154
  if isinstance(def_.addr, StackBaseOffset) and isinstance(def_.addr.offset, int):
145
155
  idx_begin = bisect_left(sorted_stackvar_offs, def_.addr.offset)
@@ -17,13 +17,24 @@ class TraversalAnalysis(ForwardAnalysis[TraversalState, ailment.Block, object, t
17
17
  TraversalAnalysis traverses the AIL graph and collects definitions.
18
18
  """
19
19
 
20
- def __init__(self, project, func, ail_graph, sp_tracker, bp_as_gpr: bool, stackvars: bool, tmps: bool):
20
+ def __init__(
21
+ self,
22
+ project,
23
+ func,
24
+ ail_graph,
25
+ sp_tracker,
26
+ bp_as_gpr: bool,
27
+ stackvars: bool,
28
+ tmps: bool,
29
+ func_args: set[ailment.Expr.VirtualVariable],
30
+ ):
21
31
 
22
32
  self.project = project
23
33
  self._stackvars = stackvars
24
34
  self._tmps = tmps
25
35
  self._function = func
26
36
  self._graph_visitor = FunctionGraphVisitor(self._function, ail_graph)
37
+ self._func_args = func_args
27
38
 
28
39
  ForwardAnalysis.__init__(
29
40
  self, order_jobs=True, allow_merging=True, allow_widening=False, graph_visitor=self._graph_visitor
@@ -52,13 +63,28 @@ class TraversalAnalysis(ForwardAnalysis[TraversalState, ailment.Block, object, t
52
63
  pass
53
64
 
54
65
  def _initial_abstract_state(self, node: ailment.Block) -> TraversalState:
55
- return TraversalState(self.project.arch, self._function)
66
+ state = TraversalState(self.project.arch, self._function)
67
+ # update it with function arguments
68
+ if self._func_args:
69
+ for func_arg in self._func_args:
70
+ if func_arg.oident[0] == ailment.Expr.VirtualVariableCategory.REGISTER:
71
+ reg_offset = func_arg.oident[1]
72
+ reg_size = func_arg.size
73
+ state.live_registers.add(reg_offset)
74
+ # get the full register if needed
75
+ basereg_offset, basereg_size = self.project.arch.get_base_register(reg_offset, size=reg_size)
76
+ if basereg_size != reg_size or basereg_offset != reg_offset:
77
+ state.live_registers.add(basereg_offset)
78
+ elif func_arg.oident[0] == ailment.Expr.VirtualVariableCategory.STACK:
79
+ state.live_stackvars.add((func_arg.oident[1], func_arg.size))
80
+ return state
56
81
 
57
82
  def _merge_states(self, node: ailment.Block, *states: TraversalState) -> tuple[TraversalState, bool]:
58
83
  merged_state = TraversalState(
59
84
  self.project.arch,
60
85
  self._function,
61
86
  live_registers=states[0].live_registers.copy(),
87
+ live_stackvars=states[0].live_stackvars.copy(),
62
88
  )
63
89
  merge_occurred = merged_state.merge(*states[1:])
64
90
  return merged_state, not merge_occurred
@@ -37,7 +37,12 @@ class TraversalState:
37
37
  merge_occurred = True
38
38
  all_regs |= o.live_registers
39
39
 
40
- # TODO: merge of live_stackvars
40
+ all_stackvars: set[tuple[int, int]] = self.live_stackvars.copy()
41
+ for o in others:
42
+ if o.live_stackvars.difference(all_stackvars):
43
+ merge_occurred = True
44
+ all_stackvars |= o.live_stackvars
41
45
 
42
46
  self.live_registers = all_regs
47
+ self.live_stackvars = all_stackvars
43
48
  return merge_occurred
@@ -679,14 +679,23 @@ class CStatements(CStatement):
679
679
  Represents a sequence of statements in C.
680
680
  """
681
681
 
682
- __slots__ = ("statements",)
682
+ __slots__ = (
683
+ "addr",
684
+ "statements",
685
+ )
683
686
 
684
- def __init__(self, statements, **kwargs):
687
+ def __init__(self, statements, addr=None, **kwargs):
685
688
  super().__init__(**kwargs)
686
689
 
687
690
  self.statements = statements
691
+ self.addr = addr
688
692
 
689
693
  def c_repr_chunks(self, indent=0, asexpr=False):
694
+ indent_str = self.indent_str(indent)
695
+ if self.codegen.display_block_addrs:
696
+ yield indent_str, None
697
+ yield f"/* Block {hex(self.addr) if self.addr is not None else 'unknown'} */", None
698
+ yield "\n", None
690
699
  for stmt in self.statements:
691
700
  yield from stmt.c_repr_chunks(indent=indent, asexpr=asexpr)
692
701
  if asexpr:
@@ -1572,15 +1581,19 @@ class CVariable(CExpression):
1572
1581
  "unified_variable",
1573
1582
  "variable",
1574
1583
  "variable_type",
1584
+ "vvar_id",
1575
1585
  )
1576
1586
 
1577
- def __init__(self, variable: SimVariable, unified_variable=None, variable_type=None, tags=None, **kwargs):
1587
+ def __init__(
1588
+ self, variable: SimVariable, unified_variable=None, variable_type=None, tags=None, vvar_id=None, **kwargs
1589
+ ):
1578
1590
  super().__init__(**kwargs)
1579
1591
 
1580
1592
  self.variable: SimVariable = variable
1581
1593
  self.unified_variable: SimVariable | None = unified_variable
1582
1594
  self.variable_type: SimType = variable_type.with_arch(self.codegen.project.arch)
1583
1595
  self.tags = tags
1596
+ self.vvar_id = vvar_id
1584
1597
 
1585
1598
  @property
1586
1599
  def type(self):
@@ -1598,6 +1611,8 @@ class CVariable(CExpression):
1598
1611
 
1599
1612
  def c_repr_chunks(self, indent=0, asexpr=False):
1600
1613
  yield self.name, self
1614
+ if self.codegen.display_vvar_ids:
1615
+ yield f"<vvar_{self.vvar_id}>", self
1601
1616
 
1602
1617
 
1603
1618
  class CIndexedVariable(CExpression):
@@ -2141,7 +2156,8 @@ class CConstant(CExpression):
2141
2156
  result = self.fmt.get("neg", None)
2142
2157
  if result is None:
2143
2158
  result = False
2144
- if isinstance(self.value, int):
2159
+ # guess it
2160
+ if isinstance(self._type, (SimTypeInt, SimTypeChar)) and self._type.signed and isinstance(self.value, int):
2145
2161
  value_size = self._type.size if self._type is not None else None
2146
2162
  if (value_size == 32 and 0xF000_0000 <= self.value <= 0xFFFF_FFFF) or (
2147
2163
  value_size == 64 and 0xF000_0000_0000_0000 <= self.value <= 0xFFFF_FFFF_FFFF_FFFF
@@ -2486,6 +2502,8 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2486
2502
  simplify_else_scope=True,
2487
2503
  cstyle_ifs=True,
2488
2504
  omit_func_header=False,
2505
+ display_block_addrs=False,
2506
+ display_vvar_ids=False,
2489
2507
  ):
2490
2508
  super().__init__(flavor=flavor)
2491
2509
 
@@ -2558,6 +2576,8 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2558
2576
  self.simplify_else_scope = simplify_else_scope
2559
2577
  self.cstyle_ifs = cstyle_ifs
2560
2578
  self.omit_func_header = omit_func_header
2579
+ self.display_block_addrs = display_block_addrs
2580
+ self.display_vvar_ids = display_vvar_ids
2561
2581
  self.text = None
2562
2582
  self.map_pos_to_node = None
2563
2583
  self.map_pos_to_addr = None
@@ -2740,7 +2760,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2740
2760
  return _mapping.get(n)(signed=signed).with_arch(self.project.arch)
2741
2761
  return SimTypeNum(n, signed=signed).with_arch(self.project.arch)
2742
2762
 
2743
- def _variable(self, variable: SimVariable, fallback_type_size: int | None) -> CVariable:
2763
+ def _variable(self, variable: SimVariable, fallback_type_size: int | None, vvar_id: int | None = None) -> CVariable:
2744
2764
  # TODO: we need to fucking make sure that variable recovery and type inference actually generates a size
2745
2765
  # TODO: for each variable it links into the fucking ail. then we can remove fallback_type_size.
2746
2766
  unified = self._variable_kb.variables[self._func.addr].unified_variable(variable)
@@ -2751,7 +2771,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
2751
2771
  variable_type = self.default_simtype_from_bits(
2752
2772
  (fallback_type_size or self.project.arch.bytes) * self.project.arch.byte_width
2753
2773
  )
2754
- cvar = CVariable(variable, unified_variable=unified, variable_type=variable_type, codegen=self)
2774
+ cvar = CVariable(variable, unified_variable=unified, variable_type=variable_type, codegen=self, vvar_id=vvar_id)
2755
2775
  self._variables_in_use[variable] = cvar
2756
2776
  return cvar
2757
2777
 
@@ -3106,14 +3126,18 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3106
3126
  # Handlers
3107
3127
  #
3108
3128
 
3109
- def _handle(self, node, is_expr: bool = True, lvalue: bool = False):
3129
+ def _handle(self, node, is_expr: bool = True, lvalue: bool = False, likely_signed=False):
3110
3130
  if (node, is_expr) in self.ailexpr2cnode:
3111
3131
  return self.ailexpr2cnode[(node, is_expr)]
3112
3132
 
3113
3133
  handler: Callable | None = self._handlers.get(node.__class__, None)
3114
3134
  if handler is not None:
3115
3135
  # special case for Call
3116
- converted = handler(node, is_expr=is_expr) if isinstance(node, Stmt.Call) else handler(node, lvalue=lvalue)
3136
+ converted = (
3137
+ handler(node, is_expr=is_expr)
3138
+ if isinstance(node, Stmt.Call)
3139
+ else handler(node, lvalue=lvalue, likely_signed=likely_signed)
3140
+ )
3117
3141
  self.ailexpr2cnode[(node, is_expr)] = converted
3118
3142
  return converted
3119
3143
  raise UnsupportedNodeTypeError(f"Node type {type(node)} is not supported yet.")
@@ -3127,10 +3151,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3127
3151
  for node in seq.nodes:
3128
3152
  lines.append(self._handle(node, is_expr=False))
3129
3153
 
3130
- if not lines:
3131
- return CStatements([], codegen=None)
3132
-
3133
- return CStatements(lines, codegen=self) if len(lines) > 1 else lines[0]
3154
+ return lines[0] if len(lines) == 1 else CStatements(lines, codegen=self, addr=seq.addr)
3134
3155
 
3135
3156
  def _handle_Loop(self, loop_node, **kwargs):
3136
3157
  tags = {"ins_addr": loop_node.addr}
@@ -3217,7 +3238,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3217
3238
  r = self._handle(n, is_expr=False)
3218
3239
  lines.append(r)
3219
3240
 
3220
- return CStatements(lines, codegen=self) if len(lines) > 1 else lines[0]
3241
+ return lines[0] if len(lines) == 1 else CStatements(lines, codegen=self, addr=node.addr)
3221
3242
 
3222
3243
  def _handle_SwitchCase(self, node, **kwargs):
3223
3244
  """
@@ -3260,7 +3281,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3260
3281
  cstmt = CUnsupportedStatement(stmt, codegen=self)
3261
3282
  cstmts.append(cstmt)
3262
3283
 
3263
- return CStatements(cstmts, codegen=self)
3284
+ return CStatements(cstmts, codegen=self, addr=node.addr)
3264
3285
 
3265
3286
  #
3266
3287
  # AIL statement handlers
@@ -3315,9 +3336,9 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3315
3336
  if stmt.dst.variable is not None:
3316
3337
  if "struct_member_info" in stmt.dst.tags:
3317
3338
  offset, var, _ = stmt.dst.struct_member_info
3318
- cvar = self._variable(var, stmt.dst.size)
3339
+ cvar = self._variable(var, stmt.dst.size, vvar_id=stmt.dst.varid)
3319
3340
  else:
3320
- cvar = self._variable(stmt.dst.variable, stmt.dst.size)
3341
+ cvar = self._variable(stmt.dst.variable, stmt.dst.size, vvar_id=stmt.dst.varid)
3321
3342
  offset = stmt.dst.variable_offset or 0
3322
3343
  assert type(offset) is int # I refuse to deal with the alternative
3323
3344
 
@@ -3474,7 +3495,9 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3474
3495
  l.warning("FIXME: Leftover Tmp expressions are found.")
3475
3496
  return self._variable(SimTemporaryVariable(expr.tmp_idx, expr.bits), expr.size)
3476
3497
 
3477
- def _handle_Expr_Const(self, expr: Expr.Const, type_=None, reference_values=None, variable=None, **kwargs):
3498
+ def _handle_Expr_Const(
3499
+ self, expr: Expr.Const, type_=None, reference_values=None, variable=None, likely_signed=True, **kwargs
3500
+ ):
3478
3501
  inline_string = False
3479
3502
  function_pointer = False
3480
3503
 
@@ -3550,8 +3573,8 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3550
3573
  inline_string = True
3551
3574
 
3552
3575
  if type_ is None:
3553
- # default to int
3554
- type_ = self.default_simtype_from_bits(expr.bits)
3576
+ # default to int or unsigned int, determined by likely_signed
3577
+ type_ = self.default_simtype_from_bits(expr.bits, signed=likely_signed)
3555
3578
 
3556
3579
  if variable is None and hasattr(expr, "reference_variable") and expr.reference_variable is not None:
3557
3580
  variable = expr.reference_variable
@@ -3583,7 +3606,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3583
3606
  )
3584
3607
 
3585
3608
  lhs = self._handle(expr.operands[0])
3586
- rhs = self._handle(expr.operands[1])
3609
+ rhs = self._handle(expr.operands[1], likely_signed=expr.op not in {"And", "Or"})
3587
3610
 
3588
3611
  return CBinaryOp(
3589
3612
  expr.op,
@@ -3679,7 +3702,7 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
3679
3702
 
3680
3703
  def _handle_VirtualVariable(self, expr: Expr.VirtualVariable, **kwargs):
3681
3704
  if expr.variable:
3682
- cvar = self._variable(expr.variable, None)
3705
+ cvar = self._variable(expr.variable, None, vvar_id=expr.varid)
3683
3706
  if expr.variable.size != expr.size:
3684
3707
  l.warning(
3685
3708
  "VirtualVariable size (%d) and variable size (%d) do not match. Force a type cast.",