angr 9.2.158__cp310-abi3-manylinux2014_x86_64.whl → 9.2.159__cp310-abi3-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 (191) hide show
  1. angr/__init__.py +1 -1
  2. angr/ailment/__init__.py +81 -0
  3. angr/ailment/block.py +81 -0
  4. angr/ailment/block_walker.py +845 -0
  5. angr/ailment/constant.py +3 -0
  6. angr/ailment/converter_common.py +11 -0
  7. angr/ailment/converter_pcode.py +623 -0
  8. angr/ailment/converter_vex.py +798 -0
  9. angr/ailment/expression.py +1639 -0
  10. angr/ailment/manager.py +33 -0
  11. angr/ailment/statement.py +978 -0
  12. angr/ailment/tagged_object.py +61 -0
  13. angr/ailment/utils.py +114 -0
  14. angr/analyses/calling_convention/calling_convention.py +6 -2
  15. angr/analyses/decompiler/ail_simplifier.py +5 -5
  16. angr/analyses/decompiler/block_io_finder.py +4 -4
  17. angr/analyses/decompiler/block_similarity.py +2 -2
  18. angr/analyses/decompiler/block_simplifier.py +4 -4
  19. angr/analyses/decompiler/callsite_maker.py +2 -2
  20. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -1
  21. angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +1 -1
  22. angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +1 -1
  23. angr/analyses/decompiler/clinic.py +1 -1
  24. angr/analyses/decompiler/condition_processor.py +1 -1
  25. angr/analyses/decompiler/counters/boolean_counter.py +4 -4
  26. angr/analyses/decompiler/counters/call_counter.py +4 -4
  27. angr/analyses/decompiler/counters/expression_counters.py +5 -5
  28. angr/analyses/decompiler/counters/seq_cf_structure_counter.py +1 -1
  29. angr/analyses/decompiler/decompiler.py +5 -3
  30. angr/analyses/decompiler/dephication/dephication_base.py +12 -1
  31. angr/analyses/decompiler/dephication/graph_dephication.py +12 -5
  32. angr/analyses/decompiler/dephication/graph_rewriting.py +6 -10
  33. angr/analyses/decompiler/dephication/graph_vvar_mapping.py +109 -72
  34. angr/analyses/decompiler/dephication/rewriting_engine.py +32 -9
  35. angr/analyses/decompiler/dephication/seqnode_dephication.py +32 -10
  36. angr/analyses/decompiler/empty_node_remover.py +2 -2
  37. angr/analyses/decompiler/expression_narrower.py +6 -6
  38. angr/analyses/decompiler/goto_manager.py +2 -2
  39. angr/analyses/decompiler/jump_target_collector.py +1 -1
  40. angr/analyses/decompiler/label_collector.py +1 -1
  41. angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +25 -25
  42. angr/analyses/decompiler/optimization_passes/call_stmt_rewriter.py +1 -1
  43. angr/analyses/decompiler/optimization_passes/code_motion.py +2 -2
  44. angr/analyses/decompiler/optimization_passes/condition_constprop.py +3 -3
  45. angr/analyses/decompiler/optimization_passes/const_derefs.py +3 -3
  46. angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +4 -4
  47. angr/analyses/decompiler/optimization_passes/deadblock_remover.py +2 -2
  48. angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +3 -3
  49. angr/analyses/decompiler/optimization_passes/div_simplifier.py +1 -1
  50. angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
  51. angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +4 -4
  52. angr/analyses/decompiler/optimization_passes/duplication_reverter/similarity.py +1 -1
  53. angr/analyses/decompiler/optimization_passes/duplication_reverter/utils.py +4 -4
  54. angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +3 -3
  55. angr/analyses/decompiler/optimization_passes/engine_base.py +1 -1
  56. angr/analyses/decompiler/optimization_passes/expr_op_swapper.py +3 -3
  57. angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +2 -2
  58. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +2 -2
  59. angr/analyses/decompiler/optimization_passes/ite_expr_converter.py +3 -3
  60. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +3 -3
  61. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +4 -4
  62. angr/analyses/decompiler/optimization_passes/mod_simplifier.py +1 -1
  63. angr/analyses/decompiler/optimization_passes/optimization_pass.py +25 -1
  64. angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +1 -1
  65. angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py +1 -1
  66. angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +2 -2
  67. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +4 -4
  68. angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +2 -2
  69. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +1 -1
  70. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +3 -3
  71. angr/analyses/decompiler/optimization_passes/switch_reused_entry_rewriter.py +3 -3
  72. angr/analyses/decompiler/optimization_passes/tag_slicer.py +1 -1
  73. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +1 -1
  74. angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +1 -1
  75. angr/analyses/decompiler/peephole_optimizations/a_div_const_add_a_mul_n_div_const.py +1 -1
  76. angr/analyses/decompiler/peephole_optimizations/a_mul_const_div_shr_const.py +1 -1
  77. angr/analyses/decompiler/peephole_optimizations/a_mul_const_sub_a.py +1 -1
  78. angr/analyses/decompiler/peephole_optimizations/a_shl_const_sub_a.py +1 -1
  79. angr/analyses/decompiler/peephole_optimizations/a_sub_a_div.py +1 -1
  80. angr/analyses/decompiler/peephole_optimizations/a_sub_a_div_const_mul_const.py +1 -1
  81. angr/analyses/decompiler/peephole_optimizations/a_sub_a_shr_const_shr_const.py +1 -1
  82. angr/analyses/decompiler/peephole_optimizations/a_sub_a_sub_n.py +1 -1
  83. angr/analyses/decompiler/peephole_optimizations/arm_cmpf.py +1 -1
  84. angr/analyses/decompiler/peephole_optimizations/base.py +3 -3
  85. angr/analyses/decompiler/peephole_optimizations/basepointeroffset_add_n.py +1 -1
  86. angr/analyses/decompiler/peephole_optimizations/basepointeroffset_and_mask.py +1 -1
  87. angr/analyses/decompiler/peephole_optimizations/bitwise_or_to_logical_or.py +1 -1
  88. angr/analyses/decompiler/peephole_optimizations/bool_expr_xor_1.py +1 -1
  89. angr/analyses/decompiler/peephole_optimizations/bswap.py +2 -2
  90. angr/analyses/decompiler/peephole_optimizations/cas_intrinsics.py +2 -2
  91. angr/analyses/decompiler/peephole_optimizations/cmpord_rewriter.py +2 -2
  92. angr/analyses/decompiler/peephole_optimizations/coalesce_adjacent_shrs.py +1 -1
  93. angr/analyses/decompiler/peephole_optimizations/coalesce_same_cascading_ifs.py +2 -2
  94. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +1 -1
  95. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
  96. angr/analyses/decompiler/peephole_optimizations/conv_a_sub0_shr_and.py +1 -1
  97. angr/analyses/decompiler/peephole_optimizations/conv_shl_shr.py +1 -1
  98. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +1 -1
  99. angr/analyses/decompiler/peephole_optimizations/extended_byte_and_mask.py +1 -1
  100. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +2 -2
  101. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +2 -2
  102. angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +2 -2
  103. angr/analyses/decompiler/peephole_optimizations/invert_negated_logical_conjuction_disjunction.py +1 -1
  104. angr/analyses/decompiler/peephole_optimizations/one_sub_bool.py +1 -1
  105. angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +1 -1
  106. angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +2 -2
  107. angr/analyses/decompiler/peephole_optimizations/remove_empty_if_body.py +2 -2
  108. angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py +1 -1
  109. angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +1 -1
  110. angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +1 -1
  111. angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_branch.py +1 -1
  112. angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_comparisons.py +1 -1
  113. angr/analyses/decompiler/peephole_optimizations/remove_redundant_nots.py +1 -1
  114. angr/analyses/decompiler/peephole_optimizations/remove_redundant_reinterprets.py +1 -1
  115. angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +1 -1
  116. angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts_around_comparators.py +1 -1
  117. angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +1 -1
  118. angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +1 -1
  119. angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +3 -3
  120. angr/analyses/decompiler/peephole_optimizations/rewrite_mips_gp_loads.py +1 -1
  121. angr/analyses/decompiler/peephole_optimizations/rol_ror.py +2 -2
  122. angr/analyses/decompiler/peephole_optimizations/sar_to_signed_div.py +1 -1
  123. angr/analyses/decompiler/peephole_optimizations/shl_to_mul.py +1 -1
  124. angr/analyses/decompiler/peephole_optimizations/simplify_pc_relative_loads.py +1 -1
  125. angr/analyses/decompiler/peephole_optimizations/single_bit_cond_to_boolexpr.py +1 -1
  126. angr/analyses/decompiler/peephole_optimizations/single_bit_xor.py +1 -1
  127. angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py +2 -2
  128. angr/analyses/decompiler/peephole_optimizations/utils.py +1 -1
  129. angr/analyses/decompiler/redundant_label_remover.py +1 -1
  130. angr/analyses/decompiler/region_identifier.py +4 -4
  131. angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py +1 -1
  132. angr/analyses/decompiler/region_simplifiers/cascading_ifs.py +1 -1
  133. angr/analyses/decompiler/region_simplifiers/expr_folding.py +37 -8
  134. angr/analyses/decompiler/region_simplifiers/goto.py +1 -1
  135. angr/analyses/decompiler/region_simplifiers/if_.py +1 -1
  136. angr/analyses/decompiler/region_simplifiers/loop.py +1 -1
  137. angr/analyses/decompiler/region_simplifiers/node_address_finder.py +1 -1
  138. angr/analyses/decompiler/region_simplifiers/region_simplifier.py +14 -2
  139. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +3 -3
  140. angr/analyses/decompiler/region_simplifiers/switch_expr_simplifier.py +1 -1
  141. angr/analyses/decompiler/return_maker.py +1 -1
  142. angr/analyses/decompiler/seq_to_blocks.py +1 -1
  143. angr/analyses/decompiler/sequence_walker.py +2 -2
  144. angr/analyses/decompiler/ssailification/rewriting.py +4 -4
  145. angr/analyses/decompiler/ssailification/rewriting_engine.py +4 -4
  146. angr/analyses/decompiler/ssailification/rewriting_state.py +3 -3
  147. angr/analyses/decompiler/ssailification/ssailification.py +2 -2
  148. angr/analyses/decompiler/ssailification/traversal.py +1 -1
  149. angr/analyses/decompiler/ssailification/traversal_engine.py +11 -2
  150. angr/analyses/decompiler/structured_codegen/c.py +3 -3
  151. angr/analyses/decompiler/structuring/dream.py +1 -1
  152. angr/analyses/decompiler/structuring/phoenix.py +3 -3
  153. angr/analyses/decompiler/structuring/structurer_base.py +1 -1
  154. angr/analyses/decompiler/structuring/structurer_nodes.py +1 -2
  155. angr/analyses/decompiler/utils.py +1 -1
  156. angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
  157. angr/analyses/deobfuscator/string_obf_opt_passes.py +3 -3
  158. angr/analyses/deobfuscator/string_obf_peephole_optimizer.py +2 -2
  159. angr/analyses/propagator/propagator.py +1 -1
  160. angr/analyses/proximity_graph.py +2 -2
  161. angr/analyses/reaching_definitions/engine_ail.py +1 -1
  162. angr/analyses/reaching_definitions/reaching_definitions.py +1 -1
  163. angr/analyses/reaching_definitions/subject.py +1 -1
  164. angr/analyses/s_liveness.py +2 -2
  165. angr/analyses/s_propagator.py +3 -3
  166. angr/analyses/s_reaching_definitions/s_rda_model.py +1 -1
  167. angr/analyses/s_reaching_definitions/s_rda_view.py +3 -3
  168. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +3 -3
  169. angr/analyses/variable_recovery/engine_ail.py +2 -2
  170. angr/analyses/variable_recovery/engine_base.py +1 -1
  171. angr/analyses/variable_recovery/variable_recovery_base.py +1 -1
  172. angr/analyses/variable_recovery/variable_recovery_fast.py +2 -2
  173. angr/engines/light/data.py +1 -1
  174. angr/engines/light/engine.py +1 -1
  175. angr/knowledge_plugins/key_definitions/atoms.py +1 -1
  176. angr/knowledge_plugins/propagations/prop_value.py +1 -1
  177. angr/knowledge_plugins/propagations/propagation_model.py +1 -1
  178. angr/knowledge_plugins/propagations/states.py +1 -1
  179. angr/knowledge_plugins/variables/variable_manager.py +1 -1
  180. angr/rustylib.abi3.so +0 -0
  181. angr/utils/ail.py +4 -4
  182. angr/utils/endness.py +1 -1
  183. angr/utils/ssa/__init__.py +14 -4
  184. angr/utils/ssa/tmp_uses_collector.py +4 -4
  185. angr/utils/ssa/vvar_uses_collector.py +4 -4
  186. {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/METADATA +6 -6
  187. {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/RECORD +191 -179
  188. {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/WHEEL +0 -0
  189. {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/entry_points.txt +0 -0
  190. {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/licenses/LICENSE +0 -0
  191. {angr-9.2.158.dist-info → angr-9.2.159.dist-info}/top_level.txt +0 -0
@@ -2,9 +2,10 @@ from __future__ import annotations
2
2
  import logging
3
3
  from collections import defaultdict
4
4
 
5
- from ailment.block import Block
6
- from ailment.expression import Phi, VirtualVariable, VirtualVariableCategory
7
- from ailment.statement import Assignment, Jump, ConditionalJump, Label
5
+ from angr.ailment import AILBlockWalker
6
+ from angr.ailment.block import Block
7
+ from angr.ailment.expression import Phi, VirtualVariable, VirtualVariableCategory
8
+ from angr.ailment.statement import Assignment, Jump, ConditionalJump, Label
8
9
 
9
10
  from angr.analyses import Analysis
10
11
  from angr.analyses.s_reaching_definitions import SRDAModel
@@ -88,6 +89,7 @@ class GraphDephicationVVarMapping(Analysis): # pylint:disable=abstract-method
88
89
  unresolved_neighbor_map = defaultdict(set)
89
90
 
90
91
  # check for interferences
92
+ candidate_vvar_set_to_phiid: defaultdict[frozenset[int], set[int]] = defaultdict(set)
91
93
  for phi_id, src_and_varids in phi_to_srcvarid.items():
92
94
  candidate_vvar_set: set[int] = set()
93
95
  src_and_varids = list(src_and_varids)
@@ -135,9 +137,13 @@ class GraphDephicationVVarMapping(Analysis): # pylint:disable=abstract-method
135
137
  if not unresolved_neighbor_map[neighbor]:
136
138
  del unresolved_neighbor_map[neighbor]
137
139
 
140
+ if candidate_vvar_set:
141
+ candidate_vvar_set_to_phiid[frozenset(candidate_vvar_set)].add(phi_id)
142
+
143
+ for vvar_set, phi_ids in candidate_vvar_set_to_phiid.items():
138
144
  # insert copies of variables as needed
139
- for varid in candidate_vvar_set:
140
- insertion_type, new_vvar_ids = self._insert_vvar_copy(varid, phi_id)
145
+ for varid in vvar_set:
146
+ insertion_type, new_vvar_ids = self._insert_vvar_copy(varid, phi_ids)
141
147
 
142
148
  if insertion_type == 0:
143
149
  for src, old_vvar_id, new_vvar_id in new_vvar_ids:
@@ -159,19 +165,20 @@ class GraphDephicationVVarMapping(Analysis): # pylint:disable=abstract-method
159
165
  interference.add_edge(new_vvar_id, vvar_id)
160
166
 
161
167
  else: # insertion_type == 1, i.e. the set has only one element
162
- phi_block_loc, old_phi_varid, new_phi_varid = next(iter(new_vvar_ids))
163
- self.copied_vvar_ids.add(new_phi_varid)
168
+ for phi_block_loc, old_phi_varid, new_phi_varid in new_vvar_ids:
169
+ self.copied_vvar_ids.add(new_phi_varid)
164
170
 
165
- phi_congruence_class[new_phi_varid] = {new_phi_varid}
171
+ phi_congruence_class[new_phi_varid] = {new_phi_varid}
166
172
 
167
- live_ins[phi_block_loc].discard(old_phi_varid)
168
- live_ins[phi_block_loc].add(new_phi_varid)
173
+ live_ins[phi_block_loc].discard(old_phi_varid)
174
+ live_ins[phi_block_loc].add(new_phi_varid)
169
175
 
170
- # update interference graph
171
- for vvar_id in live_ins[phi_block_loc]:
172
- interference.add_edge(new_phi_varid, vvar_id)
176
+ # update interference graph
177
+ for vvar_id in live_ins[phi_block_loc]:
178
+ interference.add_edge(new_phi_varid, vvar_id)
173
179
 
174
- # update phi_congruence_class
180
+ # update phi_congruence_class
181
+ for phi_id in phi_to_srcvarid:
175
182
  (phidef_block_addr, phidef_block_idx), phidef_stmt_idx = self._vvar_defloc[phi_id]
176
183
  phi_block = self._blocks[(phidef_block_addr, phidef_block_idx)]
177
184
  # phi_stmt is the newly created phi statement with variables replaced
@@ -199,82 +206,112 @@ class GraphDephicationVVarMapping(Analysis): # pylint:disable=abstract-method
199
206
 
200
207
  return mapping
201
208
 
202
- def _insert_vvar_copy(self, varid: int, phi_varid: int) -> tuple[int, set]:
203
- (phidef_block_addr, phidef_block_idx), phidef_stmt_idx = self._vvar_defloc[phi_varid]
204
- if varid != phi_varid:
209
+ def _insert_vvar_copy(
210
+ self, varid: int, phi_varids: set[int]
211
+ ) -> tuple[int, set[tuple[tuple[int, int | None], int, int]]]:
212
+ new_vvar_info: set[tuple[tuple[int, int | None], int, int]] = set()
213
+ new_vvar_id = self.vvar_id_start
214
+ self.vvar_id_start += 1
215
+
216
+ if varid not in phi_varids:
205
217
  # it's one of the source vvars
206
218
 
207
- phi_block = self._blocks[(phidef_block_addr, phidef_block_idx)]
208
- phi_stmt = phi_block.statements[phidef_stmt_idx]
219
+ stmt_appended_locs: dict[tuple[int, int | None], VirtualVariable] = {}
209
220
 
210
- new_vvar_ids = set()
211
-
212
- for src, vvar in list(phi_stmt.src.src_and_vvars):
213
- if vvar is None or vvar.varid != varid:
214
- continue
215
-
216
- new_vvar_id = self.vvar_id_start
217
- self.vvar_id_start += 1
218
-
219
- vvar = self._rd.varid_to_vvar[varid]
220
- src_block_addr, src_block_idx = src
221
-
222
- the_block = self._blocks[(src_block_addr, src_block_idx)]
223
- ins_addr = the_block.addr + the_block.original_size - 1
224
- if vvar.category == VirtualVariableCategory.PARAMETER:
225
- # it's a parameter, so we copy the variable into a dummy register vvar
226
- # a parameter vvar should never be assigned to
227
- new_category = VirtualVariableCategory.REGISTER
228
- new_oident = DEPHI_VVAR_REG_OFFSET
229
- else:
230
- new_category = vvar.category
231
- new_oident = vvar.oident
232
- new_vvar = VirtualVariable(
233
- None, new_vvar_id, vvar.bits, new_category, oident=new_oident, ins_addr=ins_addr
234
- )
235
- assignment = Assignment(None, new_vvar, vvar, ins_addr=ins_addr)
221
+ # update all phi statements
222
+ for phi_varid in phi_varids:
223
+ (phidef_block_addr, phidef_block_idx), phidef_stmt_idx = self._vvar_defloc[phi_varid]
224
+ phi_block = self._blocks[(phidef_block_addr, phidef_block_idx)]
225
+ phi_stmt = phi_block.statements[phidef_stmt_idx]
226
+
227
+ for src, vvar in list(phi_stmt.src.src_and_vvars):
228
+ if vvar is None or vvar.varid != varid:
229
+ continue
230
+
231
+ if src not in stmt_appended_locs:
232
+ # we have not yet appended a statement to this block
233
+ the_block = self._blocks[src]
234
+ ins_addr = the_block.addr + the_block.original_size - 1
235
+ if vvar.category == VirtualVariableCategory.PARAMETER:
236
+ # it's a parameter, so we copy the variable into a dummy register vvar
237
+ # a parameter vvar should never be assigned to
238
+ new_category = VirtualVariableCategory.REGISTER
239
+ new_oident = DEPHI_VVAR_REG_OFFSET
240
+ else:
241
+ new_category = vvar.category
242
+ new_oident = vvar.oident
243
+ new_vvar = VirtualVariable(
244
+ None, new_vvar_id, vvar.bits, new_category, oident=new_oident, ins_addr=ins_addr
245
+ )
246
+ assignment = Assignment(None, new_vvar, vvar, ins_addr=ins_addr)
247
+
248
+ self._append_stmt(the_block, assignment, old_vvarid=varid, new_vvarid=new_vvar_id)
249
+
250
+ stmt_appended_locs[src] = new_vvar
236
251
 
237
- self._append_stmt(the_block, assignment)
252
+ else:
253
+ new_vvar = stmt_appended_locs[src]
238
254
 
239
- # update the phi statement
240
- replaced_vvars: set[int] = set()
241
- for _, phi_used_vvar in list(phi_stmt.src.src_and_vvars):
242
- if phi_used_vvar is not None and phi_used_vvar.varid == varid and varid not in replaced_vvars:
243
- replaced, phi_stmt = phi_stmt.replace(phi_used_vvar, new_vvar)
244
- assert replaced
245
- replaced_vvars.add(varid)
246
- phi_block.statements[phidef_stmt_idx] = phi_stmt
255
+ replaced_vvars: set[int] = set()
256
+ for _, phi_used_vvar in list(phi_stmt.src.src_and_vvars):
257
+ if phi_used_vvar is not None and phi_used_vvar.varid == varid and varid not in replaced_vvars:
258
+ replaced, phi_stmt = phi_stmt.replace(phi_used_vvar, new_vvar)
259
+ assert replaced
260
+ replaced_vvars.add(varid)
261
+ phi_block.statements[phidef_stmt_idx] = phi_stmt
247
262
 
248
- new_vvar_ids.add((src, varid, new_vvar_id))
263
+ new_vvar_info.add((src, varid, new_vvar_id))
249
264
 
250
- return 0, new_vvar_ids
265
+ return 0, new_vvar_info
251
266
 
252
267
  # it's the phi assignment destination vvar
253
268
 
254
- new_vvar_id = self.vvar_id_start
255
- self.vvar_id_start += 1
269
+ for phi_varid in phi_varids:
270
+ phi_vvar = self._rd.varid_to_vvar[phi_varid]
271
+ (phidef_block_addr, phidef_block_idx), phidef_stmt_idx = self._vvar_defloc[phi_varid]
272
+ the_block = self._blocks[(phidef_block_addr, phidef_block_idx)]
273
+ ins_addr = the_block.addr
274
+ new_vvar = VirtualVariable(
275
+ None, new_vvar_id, phi_vvar.bits, phi_vvar.category, oident=phi_vvar.oident, ins_addr=ins_addr
276
+ )
277
+ assignment = Assignment(None, phi_vvar, new_vvar, ins_addr=ins_addr)
256
278
 
257
- phi_vvar = self._rd.varid_to_vvar[phi_varid]
258
- phi_block_addr, phi_block_idx = self._vvar_defloc[phi_varid][0]
259
- the_block = self._blocks[(phi_block_addr, phi_block_idx)]
260
- ins_addr = the_block.addr
261
- new_vvar = VirtualVariable(
262
- None, new_vvar_id, phi_vvar.bits, phi_vvar.category, oident=phi_vvar.oident, ins_addr=ins_addr
263
- )
264
- assignment = Assignment(None, phi_vvar, new_vvar, ins_addr=ins_addr)
279
+ phi_stmt = the_block.statements[phidef_stmt_idx]
280
+ replaced, phi_stmt = phi_stmt.replace(phi_vvar, new_vvar)
281
+ the_block.statements[phidef_stmt_idx] = phi_stmt
265
282
 
266
- phi_stmt = the_block.statements[phidef_stmt_idx]
267
- replaced, phi_stmt = phi_stmt.replace(phi_vvar, new_vvar)
268
- the_block.statements[phidef_stmt_idx] = phi_stmt
283
+ self._record_stmt_for_prepending(the_block, assignment)
269
284
 
270
- self._record_stmt_for_prepending(the_block, assignment)
285
+ new_vvar_info.add(((phidef_block_addr, phidef_block_idx), phi_varid, new_vvar_id))
271
286
 
272
- return 1, {((phi_block_addr, phi_block_idx), phi_varid, new_vvar_id)}
287
+ return 1, new_vvar_info
273
288
 
274
289
  @staticmethod
275
- def _append_stmt(block, stmt):
290
+ def _append_stmt(block, stmt, old_vvarid: int | None = None, new_vvarid: int | None = None):
291
+
292
+ def _handle_VirtualVariable( # pylint:disable=unused-argument
293
+ expr_idx: int, expr: VirtualVariable, stmt_idx: int, stmt, block: Block | None
294
+ ):
295
+ assert old_vvarid is not None and new_vvarid is not None
296
+ return (
297
+ None
298
+ if expr.varid != old_vvarid
299
+ else VirtualVariable(
300
+ None, new_vvarid, expr.bits, expr.category, oident=expr.oident, ins_addr=expr.ins_addr
301
+ )
302
+ )
303
+
276
304
  if block.statements and isinstance(block.statements[-1], (Jump, ConditionalJump)):
277
305
  block.statements.insert(len(block.statements) - 1, stmt)
306
+
307
+ # replace the vvar usage in the last statement if it's used there
308
+ if old_vvarid is not None and new_vvarid is not None:
309
+ replacer = AILBlockWalker()
310
+ replacer.expr_handlers[VirtualVariable] = _handle_VirtualVariable
311
+ new_stmt = replacer.walk_statement(block.statements[-1])
312
+ if new_stmt is not None and new_stmt is not block.statements[-1]:
313
+ block.statements[-1] = new_stmt
314
+
278
315
  else:
279
316
  block.statements.append(stmt)
280
317
 
@@ -1,9 +1,10 @@
1
1
  # pylint:disable=unused-argument,no-self-use,too-many-boolean-expressions
2
2
  from __future__ import annotations
3
+ from typing import TYPE_CHECKING
3
4
  import logging
4
5
 
5
- from ailment.block import Block
6
- from ailment.statement import (
6
+ from angr.ailment.block import Block
7
+ from angr.ailment.statement import (
7
8
  Statement,
8
9
  Assignment,
9
10
  Store,
@@ -14,7 +15,7 @@ from ailment.statement import (
14
15
  DirtyStatement,
15
16
  WeakAssignment,
16
17
  )
17
- from ailment.expression import (
18
+ from angr.ailment.expression import (
18
19
  Atom,
19
20
  Expression,
20
21
  VirtualVariable,
@@ -28,9 +29,11 @@ from ailment.expression import (
28
29
  DirtyExpression,
29
30
  Reinterpret,
30
31
  )
31
-
32
32
  from angr.engines.light import SimEngineNostmtAIL
33
33
 
34
+ if TYPE_CHECKING:
35
+ from angr import KnowledgeBase
36
+
34
37
 
35
38
  _l = logging.getLogger(__name__)
36
39
 
@@ -47,11 +50,15 @@ class SimEngineDephiRewriting(SimEngineNostmtAIL[None, Expression | None, Statem
47
50
  self,
48
51
  project,
49
52
  vvar_to_vvar: dict[int, int],
53
+ func_addr: int | None = None,
54
+ variable_kb: KnowledgeBase | None = None,
50
55
  ):
51
56
  super().__init__(project)
52
57
 
53
58
  self.vvar_to_vvar = vvar_to_vvar
54
59
  self.out_block = None
60
+ self.func_addr = func_addr
61
+ self.variable_kb = variable_kb
55
62
 
56
63
  self._stmt_handlers["IncompleteSwitchCaseHeadStatement"] = self._handle_stmt_IncompleteSwitchCaseHeadStatement
57
64
 
@@ -99,13 +106,29 @@ class SimEngineDephiRewriting(SimEngineNostmtAIL[None, Expression | None, Statem
99
106
  **stmt.dst.tags,
100
107
  )
101
108
 
102
- if new_dst is not None or new_src is not None:
103
- # ensure we do not generate vvar_A = vvar_A
104
- dst = stmt.dst if new_dst is None else new_dst
105
- src = stmt.src if new_src is None else new_src
106
- if isinstance(dst, VirtualVariable) and isinstance(src, VirtualVariable) and dst.varid == src.varid:
109
+ # ensure we do not generate vvar_A = vvar_A or var_A = var_A (even if lhs and rhs are different vvars, they
110
+ # can be mapped to the same variable)
111
+ dst = stmt.dst if new_dst is None else new_dst
112
+ src = stmt.src if new_src is None else new_src
113
+ if isinstance(dst, VirtualVariable) and isinstance(src, VirtualVariable):
114
+ if dst.varid == src.varid:
107
115
  # skip it
108
116
  return ()
117
+ if (
118
+ self.func_addr is not None
119
+ and self.variable_kb is not None
120
+ and self.func_addr in self.variable_kb.variables
121
+ ):
122
+ dst_var = getattr(dst, "variable", None)
123
+ src_var = getattr(src, "variable", None)
124
+ var_manager = self.variable_kb.variables[self.func_addr]
125
+ if (
126
+ dst_var is not None
127
+ and src_var is not None
128
+ and var_manager.unified_variable(dst_var) is var_manager.unified_variable(src_var)
129
+ ):
130
+ # skip it
131
+ return ()
109
132
 
110
133
  return Assignment(stmt.idx, dst, src, **stmt.tags)
111
134
  return None
@@ -1,11 +1,11 @@
1
1
  from __future__ import annotations
2
2
  from collections import defaultdict
3
3
  import logging
4
- from typing import Any
4
+ from typing import Any, TYPE_CHECKING
5
5
 
6
- from ailment.block import Block
7
- from ailment.statement import Assignment
8
- from ailment.expression import VirtualVariable, Phi, BinaryOp, UnaryOp
6
+ from angr.ailment.block import Block
7
+ from angr.ailment.statement import Assignment
8
+ from angr.ailment.expression import VirtualVariable, Phi, BinaryOp, UnaryOp
9
9
 
10
10
  import angr
11
11
  from angr.utils.ail import is_phi_assignment
@@ -16,6 +16,9 @@ from angr.analyses.decompiler.sequence_walker import SequenceWalker
16
16
  from .dephication_base import DephicationBase
17
17
  from .rewriting_engine import SimEngineDephiRewriting
18
18
 
19
+ if TYPE_CHECKING:
20
+ from angr import KnowledgeBase
21
+
19
22
 
20
23
  l = logging.getLogger(__name__)
21
24
 
@@ -54,7 +57,14 @@ class SeqNodeRewriter(SequenceWalker):
54
57
  variables.
55
58
  """
56
59
 
57
- def __init__(self, seq_node: SequenceNode, vvar_to_vvar: dict[int, int], project: angr.Project):
60
+ def __init__(
61
+ self,
62
+ seq_node: SequenceNode,
63
+ vvar_to_vvar: dict[int, int],
64
+ project: angr.Project,
65
+ variable_kb: KnowledgeBase | None = None,
66
+ func_addr: int | None = None,
67
+ ):
58
68
  super().__init__(
59
69
  handlers={
60
70
  Block: self._handle_Block,
@@ -67,7 +77,7 @@ class SeqNodeRewriter(SequenceWalker):
67
77
  )
68
78
 
69
79
  self.vvar_to_vvar = vvar_to_vvar
70
- self.engine = SimEngineDephiRewriting(project, self.vvar_to_vvar)
80
+ self.engine = SimEngineDephiRewriting(project, self.vvar_to_vvar, func_addr=func_addr, variable_kb=variable_kb)
71
81
 
72
82
  self.output = self.walk(seq_node)
73
83
  if self.output is None:
@@ -109,13 +119,19 @@ class SeqNodeRewriter(SequenceWalker):
109
119
 
110
120
  class SeqNodeDephication(DephicationBase):
111
121
  """
112
- SeqNodeDephication removes phi expressions from an AIL SeqNode and its children.
122
+ SeqNodeDephication removes phi expressions from a SequenceNode and its children. It also removes redundant variable
123
+ assignments, e.g., `vvar_2 = vvar_1` where both vvar_1 and vvar_2 are mapped to the same variable.
113
124
  """
114
125
 
115
126
  def __init__(
116
- self, func: Function | str, seq_node, vvar_to_vvar_mapping: dict[int, int] | None = None, rewrite: bool = False
127
+ self,
128
+ func: Function | str,
129
+ seq_node,
130
+ vvar_to_vvar_mapping: dict[int, int] | None = None,
131
+ rewrite: bool = False,
132
+ variable_kb: KnowledgeBase | None = None,
117
133
  ):
118
- super().__init__(func, vvar_to_vvar_mapping=vvar_to_vvar_mapping, rewrite=rewrite)
134
+ super().__init__(func, vvar_to_vvar_mapping=vvar_to_vvar_mapping, rewrite=rewrite, variable_kb=variable_kb)
119
135
 
120
136
  self._seq_node = seq_node
121
137
 
@@ -127,7 +143,13 @@ class SeqNodeDephication(DephicationBase):
127
143
  return collector.phi_to_src
128
144
 
129
145
  def _rewrite_container(self) -> Any:
130
- rewriter = SeqNodeRewriter(self._seq_node, self.vvar_to_vvar_mapping, self.project)
146
+ rewriter = SeqNodeRewriter(
147
+ self._seq_node,
148
+ self.vvar_to_vvar_mapping,
149
+ self.project,
150
+ func_addr=self._function.addr,
151
+ variable_kb=self.variable_kb,
152
+ )
131
153
  return rewriter.output
132
154
 
133
155
 
@@ -3,8 +3,8 @@ from __future__ import annotations
3
3
  from collections import OrderedDict
4
4
 
5
5
  import claripy
6
- import ailment
7
- from ailment.expression import negate
6
+ import angr.ailment as ailment
7
+ from angr.ailment.expression import negate
8
8
 
9
9
  from .sequence_walker import SequenceWalker
10
10
  from .structuring.structurer_nodes import (
@@ -3,15 +3,15 @@ from typing import Any, TYPE_CHECKING
3
3
  from collections import defaultdict
4
4
  import logging
5
5
 
6
- from ailment import AILBlockWalkerBase, AILBlockWalker
7
- from ailment.statement import Assignment, Call
8
- from ailment.expression import VirtualVariable, Convert, BinaryOp, Phi
6
+ from angr.ailment import AILBlockWalkerBase, AILBlockWalker
7
+ from angr.ailment.statement import Assignment, Call
8
+ from angr.ailment.expression import VirtualVariable, Convert, BinaryOp, Phi
9
9
 
10
10
  from angr.knowledge_plugins.key_definitions import atoms
11
11
  from angr.code_location import CodeLocation
12
12
 
13
13
  if TYPE_CHECKING:
14
- from ailment.expression import (
14
+ from angr.ailment.expression import (
15
15
  Expression,
16
16
  Load,
17
17
  UnaryOp,
@@ -19,8 +19,8 @@ if TYPE_CHECKING:
19
19
  DirtyExpression,
20
20
  VEXCCallExpression,
21
21
  )
22
- from ailment.statement import Statement
23
- from ailment.block import Block
22
+ from angr.ailment.statement import Statement
23
+ from angr.ailment.block import Block
24
24
 
25
25
 
26
26
  _l = logging.getLogger(__name__)
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
- import ailment
3
- from ailment.block import Block
2
+ import angr.ailment as ailment
3
+ from angr.ailment.block import Block
4
4
  import networkx
5
5
 
6
6
  from .utils import find_block_by_addr
@@ -1,7 +1,7 @@
1
1
  # pylint:disable=unused-argument
2
2
  from __future__ import annotations
3
3
 
4
- import ailment
4
+ import angr.ailment as ailment
5
5
 
6
6
  from .sequence_walker import SequenceWalker
7
7
 
@@ -2,7 +2,7 @@
2
2
  from __future__ import annotations
3
3
  from collections import defaultdict
4
4
 
5
- import ailment
5
+ import angr.ailment as ailment
6
6
 
7
7
  from .sequence_walker import SequenceWalker
8
8
 
@@ -2,7 +2,7 @@
2
2
  from __future__ import annotations
3
3
  import logging
4
4
 
5
- import ailment
5
+ import angr.ailment as ailment
6
6
 
7
7
  from angr.analyses.decompiler.stack_item import StackItem, StackItemType
8
8
  from .optimization_pass import OptimizationPass, OptimizationPassStage
@@ -88,32 +88,32 @@ class BasePointerSaveSimplifier(OptimizationPass):
88
88
  :rtype: tuple|None
89
89
  """
90
90
 
91
- first_block = self._get_block(self._func.addr)
92
- if first_block is None:
93
- return None
94
-
95
- for idx, stmt in enumerate(first_block.statements):
96
- if (
97
- isinstance(stmt, ailment.Stmt.Assignment)
98
- and isinstance(stmt.dst, ailment.Expr.VirtualVariable)
99
- and stmt.dst.was_stack
100
- and stmt.dst.stack_offset < 0
101
- ):
102
- if (
103
- isinstance(stmt.src, ailment.Expr.VirtualVariable)
104
- and stmt.src.was_reg
105
- and stmt.src.reg_offset == self.project.arch.bp_offset
106
- ):
107
- return first_block, idx, stmt.dst
108
- if isinstance(stmt.src, ailment.Expr.StackBaseOffset) and stmt.src.offset == 0:
109
- return first_block, idx, stmt.dst
91
+ # scan the first N blocks of the function until we find the first baseptr save statement
92
+ max_level = 5
93
+
94
+ for block in self.bfs_nodes(depth=max_level):
95
+ for idx, stmt in enumerate(block.statements):
110
96
  if (
111
- isinstance(stmt.src, ailment.Expr.UnaryOp)
112
- and isinstance(stmt.src.operand, ailment.Expr.VirtualVariable)
113
- and stmt.src.operand.was_stack
114
- and stmt.src.operand.stack_offset == 0
97
+ isinstance(stmt, ailment.Stmt.Assignment)
98
+ and isinstance(stmt.dst, ailment.Expr.VirtualVariable)
99
+ and stmt.dst.was_stack
100
+ and stmt.dst.stack_offset < 0
115
101
  ):
116
- return first_block, idx, stmt.dst
102
+ if (
103
+ isinstance(stmt.src, ailment.Expr.VirtualVariable)
104
+ and stmt.src.was_reg
105
+ and stmt.src.reg_offset == self.project.arch.bp_offset
106
+ ):
107
+ return block, idx, stmt.dst
108
+ if isinstance(stmt.src, ailment.Expr.StackBaseOffset) and stmt.src.offset == 0:
109
+ return block, idx, stmt.dst
110
+ if (
111
+ isinstance(stmt.src, ailment.Expr.UnaryOp)
112
+ and isinstance(stmt.src.operand, ailment.Expr.VirtualVariable)
113
+ and stmt.src.operand.was_stack
114
+ and stmt.src.operand.stack_offset == 0
115
+ ):
116
+ return block, idx, stmt.dst
117
117
 
118
118
  # Not found
119
119
  return None
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
  import logging
3
3
 
4
- from ailment.statement import Call, Assignment
4
+ from angr.ailment.statement import Call, Assignment
5
5
 
6
6
  from .optimization_pass import OptimizationPass, OptimizationPassStage
7
7
 
@@ -2,8 +2,8 @@ from __future__ import annotations
2
2
  import itertools
3
3
  import logging
4
4
 
5
- from ailment import Block
6
- from ailment.statement import Jump, ConditionalJump, Statement, DirtyStatement
5
+ from angr.ailment import Block
6
+ from angr.ailment.statement import Jump, ConditionalJump, Statement, DirtyStatement
7
7
  import networkx as nx
8
8
 
9
9
  from angr.analyses.decompiler.optimization_passes.optimization_pass import OptimizationPass, OptimizationPassStage
@@ -4,9 +4,9 @@ from collections import defaultdict
4
4
 
5
5
  import networkx
6
6
 
7
- from ailment import AILBlockWalker, Block
8
- from ailment.statement import ConditionalJump, Statement, Assignment
9
- from ailment.expression import Const, BinaryOp, VirtualVariable
7
+ from angr.ailment import AILBlockWalker, Block
8
+ from angr.ailment.statement import ConditionalJump, Statement, Assignment
9
+ from angr.ailment.expression import Const, BinaryOp, VirtualVariable
10
10
 
11
11
  from angr.analyses.decompiler.utils import first_nonlabel_nonphi_statement
12
12
  from angr.utils.graph import dominates
@@ -3,9 +3,9 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING
4
4
  import logging
5
5
 
6
- from ailment import Block, AILBlockWalker
7
- from ailment.expression import Load, Const, BinaryOp, UnaryOp
8
- from ailment.statement import Statement, Assignment, Call, ConditionalJump
6
+ from angr.ailment import Block, AILBlockWalker
7
+ from angr.ailment.expression import Load, Const, BinaryOp, UnaryOp
8
+ from angr.ailment.statement import Statement, Assignment, Call, ConditionalJump
9
9
 
10
10
  from angr.analyses.decompiler.ailgraph_walker import AILGraphWalker
11
11
  from .optimization_pass import OptimizationPass, OptimizationPassStage
@@ -5,10 +5,10 @@ import itertools
5
5
 
6
6
  import networkx
7
7
  import claripy
8
- from ailment import Const
9
- from ailment.block_walker import AILBlockWalkerBase
10
- from ailment.statement import Call, Statement, ConditionalJump, Assignment, Store, Return
11
- from ailment.expression import Convert, Register, Expression, Load
8
+ from angr.ailment import Const
9
+ from angr.ailment.block_walker import AILBlockWalkerBase
10
+ from angr.ailment.statement import Call, Statement, ConditionalJump, Assignment, Store, Return
11
+ from angr.ailment.expression import Convert, Register, Expression, Load
12
12
 
13
13
  from .optimization_pass import OptimizationPass, OptimizationPassStage
14
14
  from angr.analyses.decompiler.structuring import SAILRStructurer, DreamStructurer
@@ -6,8 +6,8 @@ import networkx
6
6
 
7
7
  import claripy
8
8
 
9
- from ailment.statement import Jump
10
- from ailment.expression import Const
9
+ from angr.ailment.statement import Jump
10
+ from angr.ailment.expression import Const
11
11
  from angr.utils.graph import to_acyclic_graph
12
12
  from angr.analyses.decompiler.condition_processor import ConditionProcessor
13
13
  from .optimization_pass import OptimizationPass, OptimizationPassStage
@@ -1,9 +1,9 @@
1
1
  from __future__ import annotations
2
2
  import logging
3
3
 
4
- from ailment.constant import UNDETERMINED_SIZE
5
- from ailment.expression import BinaryOp, Load, Const
6
- from ailment.statement import Assignment, WeakAssignment
4
+ from angr.ailment.constant import UNDETERMINED_SIZE
5
+ from angr.ailment.expression import BinaryOp, Load, Const
6
+ from angr.ailment.statement import Assignment, WeakAssignment
7
7
 
8
8
  from .optimization_pass import OptimizationPass, OptimizationPassStage
9
9
 
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import logging
4
4
  import math
5
5
 
6
- from ailment import Expr
6
+ from angr.ailment import Expr
7
7
  from unique_log_filter import UniqueLogFilter
8
8
 
9
9
  from .engine_base import SimplifierAILEngine, SimplifierAILState