angr 9.2.192__cp311-cp311-macosx_10_12_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1442) hide show
  1. angr/__init__.py +366 -0
  2. angr/__main__.py +182 -0
  3. angr/ail_callable.py +79 -0
  4. angr/ailment/__init__.py +83 -0
  5. angr/ailment/block.py +88 -0
  6. angr/ailment/block_walker.py +856 -0
  7. angr/ailment/constant.py +3 -0
  8. angr/ailment/converter_common.py +11 -0
  9. angr/ailment/converter_pcode.py +648 -0
  10. angr/ailment/converter_vex.py +829 -0
  11. angr/ailment/expression.py +1655 -0
  12. angr/ailment/manager.py +34 -0
  13. angr/ailment/statement.py +973 -0
  14. angr/ailment/tagged_object.py +58 -0
  15. angr/ailment/utils.py +114 -0
  16. angr/analyses/__init__.py +117 -0
  17. angr/analyses/analysis.py +429 -0
  18. angr/analyses/backward_slice.py +686 -0
  19. angr/analyses/binary_optimizer.py +670 -0
  20. angr/analyses/bindiff.py +1512 -0
  21. angr/analyses/boyscout.py +76 -0
  22. angr/analyses/callee_cleanup_finder.py +74 -0
  23. angr/analyses/calling_convention/__init__.py +6 -0
  24. angr/analyses/calling_convention/calling_convention.py +1113 -0
  25. angr/analyses/calling_convention/fact_collector.py +647 -0
  26. angr/analyses/calling_convention/utils.py +60 -0
  27. angr/analyses/cdg.py +189 -0
  28. angr/analyses/cfg/__init__.py +23 -0
  29. angr/analyses/cfg/cfb.py +451 -0
  30. angr/analyses/cfg/cfg.py +74 -0
  31. angr/analyses/cfg/cfg_arch_options.py +95 -0
  32. angr/analyses/cfg/cfg_base.py +2954 -0
  33. angr/analyses/cfg/cfg_emulated.py +3451 -0
  34. angr/analyses/cfg/cfg_fast.py +5431 -0
  35. angr/analyses/cfg/cfg_fast_soot.py +662 -0
  36. angr/analyses/cfg/cfg_job_base.py +203 -0
  37. angr/analyses/cfg/indirect_jump_resolvers/__init__.py +30 -0
  38. angr/analyses/cfg/indirect_jump_resolvers/aarch64_macho_got.py +77 -0
  39. angr/analyses/cfg/indirect_jump_resolvers/amd64_elf_got.py +62 -0
  40. angr/analyses/cfg/indirect_jump_resolvers/amd64_pe_iat.py +51 -0
  41. angr/analyses/cfg/indirect_jump_resolvers/arm_elf_fast.py +159 -0
  42. angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +339 -0
  43. angr/analyses/cfg/indirect_jump_resolvers/constant_value_manager.py +107 -0
  44. angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +82 -0
  45. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +2490 -0
  46. angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
  47. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +286 -0
  48. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_got.py +148 -0
  49. angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +46 -0
  50. angr/analyses/cfg/indirect_jump_resolvers/resolver.py +74 -0
  51. angr/analyses/cfg/indirect_jump_resolvers/syscall_resolver.py +92 -0
  52. angr/analyses/cfg/indirect_jump_resolvers/x86_elf_pic_plt.py +88 -0
  53. angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +47 -0
  54. angr/analyses/cfg_slice_to_sink/__init__.py +11 -0
  55. angr/analyses/cfg_slice_to_sink/cfg_slice_to_sink.py +117 -0
  56. angr/analyses/cfg_slice_to_sink/graph.py +87 -0
  57. angr/analyses/cfg_slice_to_sink/transitions.py +27 -0
  58. angr/analyses/class_identifier.py +63 -0
  59. angr/analyses/code_tagging.py +123 -0
  60. angr/analyses/codecave.py +77 -0
  61. angr/analyses/complete_calling_conventions.py +475 -0
  62. angr/analyses/congruency_check.py +377 -0
  63. angr/analyses/data_dep/__init__.py +16 -0
  64. angr/analyses/data_dep/data_dependency_analysis.py +595 -0
  65. angr/analyses/data_dep/dep_nodes.py +171 -0
  66. angr/analyses/data_dep/sim_act_location.py +49 -0
  67. angr/analyses/datagraph_meta.py +105 -0
  68. angr/analyses/ddg.py +1670 -0
  69. angr/analyses/decompiler/__init__.py +41 -0
  70. angr/analyses/decompiler/ail_simplifier.py +2246 -0
  71. angr/analyses/decompiler/ailgraph_walker.py +49 -0
  72. angr/analyses/decompiler/block_io_finder.py +302 -0
  73. angr/analyses/decompiler/block_similarity.py +199 -0
  74. angr/analyses/decompiler/block_simplifier.py +397 -0
  75. angr/analyses/decompiler/callsite_maker.py +579 -0
  76. angr/analyses/decompiler/ccall_rewriters/__init__.py +9 -0
  77. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +618 -0
  78. angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +24 -0
  79. angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +354 -0
  80. angr/analyses/decompiler/clinic.py +3662 -0
  81. angr/analyses/decompiler/condition_processor.py +1323 -0
  82. angr/analyses/decompiler/counters/__init__.py +16 -0
  83. angr/analyses/decompiler/counters/boolean_counter.py +27 -0
  84. angr/analyses/decompiler/counters/call_counter.py +77 -0
  85. angr/analyses/decompiler/counters/expression_counters.py +77 -0
  86. angr/analyses/decompiler/counters/seq_cf_structure_counter.py +63 -0
  87. angr/analyses/decompiler/decompilation_cache.py +54 -0
  88. angr/analyses/decompiler/decompilation_options.py +317 -0
  89. angr/analyses/decompiler/decompiler.py +796 -0
  90. angr/analyses/decompiler/dephication/__init__.py +6 -0
  91. angr/analyses/decompiler/dephication/dephication_base.py +100 -0
  92. angr/analyses/decompiler/dephication/graph_dephication.py +70 -0
  93. angr/analyses/decompiler/dephication/graph_rewriting.py +112 -0
  94. angr/analyses/decompiler/dephication/graph_vvar_mapping.py +357 -0
  95. angr/analyses/decompiler/dephication/rewriting_engine.py +528 -0
  96. angr/analyses/decompiler/dephication/seqnode_dephication.py +156 -0
  97. angr/analyses/decompiler/dirty_rewriters/__init__.py +7 -0
  98. angr/analyses/decompiler/dirty_rewriters/amd64_dirty.py +74 -0
  99. angr/analyses/decompiler/dirty_rewriters/rewriter_base.py +27 -0
  100. angr/analyses/decompiler/empty_node_remover.py +212 -0
  101. angr/analyses/decompiler/expression_narrower.py +290 -0
  102. angr/analyses/decompiler/goto_manager.py +112 -0
  103. angr/analyses/decompiler/graph_region.py +441 -0
  104. angr/analyses/decompiler/jump_target_collector.py +37 -0
  105. angr/analyses/decompiler/jumptable_entry_condition_rewriter.py +67 -0
  106. angr/analyses/decompiler/label_collector.py +32 -0
  107. angr/analyses/decompiler/node_replacer.py +42 -0
  108. angr/analyses/decompiler/notes/__init__.py +9 -0
  109. angr/analyses/decompiler/notes/decompilation_note.py +48 -0
  110. angr/analyses/decompiler/notes/deobfuscated_strings.py +56 -0
  111. angr/analyses/decompiler/optimization_passes/__init__.py +164 -0
  112. angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +157 -0
  113. angr/analyses/decompiler/optimization_passes/call_stmt_rewriter.py +46 -0
  114. angr/analyses/decompiler/optimization_passes/code_motion.py +362 -0
  115. angr/analyses/decompiler/optimization_passes/condition_constprop.py +211 -0
  116. angr/analyses/decompiler/optimization_passes/const_derefs.py +127 -0
  117. angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +365 -0
  118. angr/analyses/decompiler/optimization_passes/cross_jump_reverter.py +106 -0
  119. angr/analyses/decompiler/optimization_passes/deadblock_remover.py +82 -0
  120. angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
  121. angr/analyses/decompiler/optimization_passes/div_simplifier.py +425 -0
  122. angr/analyses/decompiler/optimization_passes/duplication_reverter/__init__.py +5 -0
  123. angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +503 -0
  124. angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +1221 -0
  125. angr/analyses/decompiler/optimization_passes/duplication_reverter/errors.py +16 -0
  126. angr/analyses/decompiler/optimization_passes/duplication_reverter/similarity.py +126 -0
  127. angr/analyses/decompiler/optimization_passes/duplication_reverter/utils.py +167 -0
  128. angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +236 -0
  129. angr/analyses/decompiler/optimization_passes/eager_std_string_eval.py +186 -0
  130. angr/analyses/decompiler/optimization_passes/engine_base.py +502 -0
  131. angr/analyses/decompiler/optimization_passes/expr_op_swapper.py +138 -0
  132. angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +113 -0
  133. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +618 -0
  134. angr/analyses/decompiler/optimization_passes/inlined_strlen_simplifier.py +274 -0
  135. angr/analyses/decompiler/optimization_passes/ite_expr_converter.py +224 -0
  136. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +337 -0
  137. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +939 -0
  138. angr/analyses/decompiler/optimization_passes/mod_simplifier.py +99 -0
  139. angr/analyses/decompiler/optimization_passes/optimization_pass.py +710 -0
  140. angr/analyses/decompiler/optimization_passes/peephole_simplifier.py +75 -0
  141. angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +263 -0
  142. angr/analyses/decompiler/optimization_passes/register_save_area_simplifier_adv.py +198 -0
  143. angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py +171 -0
  144. angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +222 -0
  145. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +632 -0
  146. angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +61 -0
  147. angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +166 -0
  148. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +333 -0
  149. angr/analyses/decompiler/optimization_passes/static_vvar_rewriter.py +336 -0
  150. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +166 -0
  151. angr/analyses/decompiler/optimization_passes/switch_reused_entry_rewriter.py +102 -0
  152. angr/analyses/decompiler/optimization_passes/tag_slicer.py +41 -0
  153. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +477 -0
  154. angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +88 -0
  155. angr/analyses/decompiler/peephole_optimizations/__init__.py +136 -0
  156. angr/analyses/decompiler/peephole_optimizations/a_div_const_add_a_mul_n_div_const.py +42 -0
  157. angr/analyses/decompiler/peephole_optimizations/a_mul_const_div_shr_const.py +38 -0
  158. angr/analyses/decompiler/peephole_optimizations/a_mul_const_sub_a.py +34 -0
  159. angr/analyses/decompiler/peephole_optimizations/a_shl_const_sub_a.py +34 -0
  160. angr/analyses/decompiler/peephole_optimizations/a_sub_a_div.py +25 -0
  161. angr/analyses/decompiler/peephole_optimizations/a_sub_a_shr_const_shr_const.py +37 -0
  162. angr/analyses/decompiler/peephole_optimizations/a_sub_a_sub_n.py +23 -0
  163. angr/analyses/decompiler/peephole_optimizations/arm_cmpf.py +236 -0
  164. angr/analyses/decompiler/peephole_optimizations/base.py +157 -0
  165. angr/analyses/decompiler/peephole_optimizations/basepointeroffset_add_n.py +34 -0
  166. angr/analyses/decompiler/peephole_optimizations/basepointeroffset_and_mask.py +36 -0
  167. angr/analyses/decompiler/peephole_optimizations/bitwise_or_to_logical_or.py +34 -0
  168. angr/analyses/decompiler/peephole_optimizations/bool_expr_xor_1.py +27 -0
  169. angr/analyses/decompiler/peephole_optimizations/bswap.py +142 -0
  170. angr/analyses/decompiler/peephole_optimizations/cas_intrinsics.py +182 -0
  171. angr/analyses/decompiler/peephole_optimizations/cmpord_rewriter.py +71 -0
  172. angr/analyses/decompiler/peephole_optimizations/coalesce_adjacent_shrs.py +39 -0
  173. angr/analyses/decompiler/peephole_optimizations/coalesce_same_cascading_ifs.py +28 -0
  174. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +44 -0
  175. angr/analyses/decompiler/peephole_optimizations/conv_a_sub0_shr_and.py +69 -0
  176. angr/analyses/decompiler/peephole_optimizations/conv_shl_shr.py +52 -0
  177. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +436 -0
  178. angr/analyses/decompiler/peephole_optimizations/extended_byte_and_mask.py +56 -0
  179. angr/analyses/decompiler/peephole_optimizations/inlined_memcpy.py +78 -0
  180. angr/analyses/decompiler/peephole_optimizations/inlined_memset.py +262 -0
  181. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +217 -0
  182. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +106 -0
  183. angr/analyses/decompiler/peephole_optimizations/inlined_wcscpy.py +256 -0
  184. angr/analyses/decompiler/peephole_optimizations/inlined_wcscpy_consolidation.py +296 -0
  185. angr/analyses/decompiler/peephole_optimizations/invert_negated_logical_conjuction_disjunction.py +50 -0
  186. angr/analyses/decompiler/peephole_optimizations/modulo_simplifier.py +89 -0
  187. angr/analyses/decompiler/peephole_optimizations/one_sub_bool.py +33 -0
  188. angr/analyses/decompiler/peephole_optimizations/optimized_div_simplifier.py +356 -0
  189. angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +45 -0
  190. angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
  191. angr/analyses/decompiler/peephole_optimizations/remove_empty_if_body.py +46 -0
  192. angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py +47 -0
  193. angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +125 -0
  194. angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +273 -0
  195. angr/analyses/decompiler/peephole_optimizations/remove_redundant_derefs.py +21 -0
  196. angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_branch.py +30 -0
  197. angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_comparisons.py +54 -0
  198. angr/analyses/decompiler/peephole_optimizations/remove_redundant_nots.py +36 -0
  199. angr/analyses/decompiler/peephole_optimizations/remove_redundant_reinterprets.py +44 -0
  200. angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +95 -0
  201. angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts_around_comparators.py +115 -0
  202. angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +85 -0
  203. angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
  204. angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
  205. angr/analyses/decompiler/peephole_optimizations/rewrite_mips_gp_loads.py +49 -0
  206. angr/analyses/decompiler/peephole_optimizations/rol_ror.py +130 -0
  207. angr/analyses/decompiler/peephole_optimizations/sar_to_signed_div.py +143 -0
  208. angr/analyses/decompiler/peephole_optimizations/shl_to_mul.py +25 -0
  209. angr/analyses/decompiler/peephole_optimizations/simplify_pc_relative_loads.py +51 -0
  210. angr/analyses/decompiler/peephole_optimizations/single_bit_cond_to_boolexpr.py +28 -0
  211. angr/analyses/decompiler/peephole_optimizations/single_bit_xor.py +29 -0
  212. angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py +131 -0
  213. angr/analyses/decompiler/peephole_optimizations/utils.py +18 -0
  214. angr/analyses/decompiler/presets/__init__.py +22 -0
  215. angr/analyses/decompiler/presets/basic.py +36 -0
  216. angr/analyses/decompiler/presets/fast.py +66 -0
  217. angr/analyses/decompiler/presets/full.py +76 -0
  218. angr/analyses/decompiler/presets/malware.py +70 -0
  219. angr/analyses/decompiler/presets/preset.py +37 -0
  220. angr/analyses/decompiler/redundant_label_remover.py +141 -0
  221. angr/analyses/decompiler/region_identifier.py +1319 -0
  222. angr/analyses/decompiler/region_simplifiers/__init__.py +5 -0
  223. angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py +95 -0
  224. angr/analyses/decompiler/region_simplifiers/cascading_ifs.py +82 -0
  225. angr/analyses/decompiler/region_simplifiers/expr_folding.py +838 -0
  226. angr/analyses/decompiler/region_simplifiers/goto.py +178 -0
  227. angr/analyses/decompiler/region_simplifiers/if_.py +135 -0
  228. angr/analyses/decompiler/region_simplifiers/ifelse.py +91 -0
  229. angr/analyses/decompiler/region_simplifiers/loop.py +143 -0
  230. angr/analyses/decompiler/region_simplifiers/node_address_finder.py +24 -0
  231. angr/analyses/decompiler/region_simplifiers/region_simplifier.py +270 -0
  232. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +654 -0
  233. angr/analyses/decompiler/region_simplifiers/switch_expr_simplifier.py +87 -0
  234. angr/analyses/decompiler/region_walker.py +24 -0
  235. angr/analyses/decompiler/return_maker.py +72 -0
  236. angr/analyses/decompiler/semantic_naming/__init__.py +37 -0
  237. angr/analyses/decompiler/semantic_naming/array_index_naming.py +196 -0
  238. angr/analyses/decompiler/semantic_naming/boolean_naming.py +264 -0
  239. angr/analyses/decompiler/semantic_naming/call_result_naming.py +220 -0
  240. angr/analyses/decompiler/semantic_naming/naming_base.py +166 -0
  241. angr/analyses/decompiler/semantic_naming/orchestrator.py +107 -0
  242. angr/analyses/decompiler/semantic_naming/pointer_naming.py +334 -0
  243. angr/analyses/decompiler/semantic_naming/region_loop_counter_naming.py +246 -0
  244. angr/analyses/decompiler/semantic_naming/size_naming.py +137 -0
  245. angr/analyses/decompiler/seq_to_blocks.py +20 -0
  246. angr/analyses/decompiler/sequence_walker.py +261 -0
  247. angr/analyses/decompiler/ssailification/__init__.py +4 -0
  248. angr/analyses/decompiler/ssailification/rewriting.py +451 -0
  249. angr/analyses/decompiler/ssailification/rewriting_engine.py +1091 -0
  250. angr/analyses/decompiler/ssailification/rewriting_state.py +61 -0
  251. angr/analyses/decompiler/ssailification/ssailification.py +283 -0
  252. angr/analyses/decompiler/ssailification/traversal.py +127 -0
  253. angr/analyses/decompiler/ssailification/traversal_engine.py +323 -0
  254. angr/analyses/decompiler/ssailification/traversal_state.py +48 -0
  255. angr/analyses/decompiler/stack_item.py +36 -0
  256. angr/analyses/decompiler/structured_codegen/__init__.py +25 -0
  257. angr/analyses/decompiler/structured_codegen/base.py +193 -0
  258. angr/analyses/decompiler/structured_codegen/c.py +4257 -0
  259. angr/analyses/decompiler/structured_codegen/dummy.py +15 -0
  260. angr/analyses/decompiler/structured_codegen/dwarf_import.py +190 -0
  261. angr/analyses/decompiler/structuring/__init__.py +30 -0
  262. angr/analyses/decompiler/structuring/dream.py +1217 -0
  263. angr/analyses/decompiler/structuring/phoenix.py +3636 -0
  264. angr/analyses/decompiler/structuring/recursive_structurer.py +187 -0
  265. angr/analyses/decompiler/structuring/sailr.py +120 -0
  266. angr/analyses/decompiler/structuring/structurer_base.py +1140 -0
  267. angr/analyses/decompiler/structuring/structurer_nodes.py +442 -0
  268. angr/analyses/decompiler/utils.py +1224 -0
  269. angr/analyses/deobfuscator/__init__.py +23 -0
  270. angr/analyses/deobfuscator/api_obf_finder.py +333 -0
  271. angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +80 -0
  272. angr/analyses/deobfuscator/api_obf_type2_finder.py +166 -0
  273. angr/analyses/deobfuscator/data_transformation_embedder.py +633 -0
  274. angr/analyses/deobfuscator/hash_lookup_api_deobfuscator.py +156 -0
  275. angr/analyses/deobfuscator/irsb_reg_collector.py +54 -0
  276. angr/analyses/deobfuscator/scope_ops_analyzer.py +68 -0
  277. angr/analyses/deobfuscator/string_obf_finder.py +983 -0
  278. angr/analyses/deobfuscator/string_obf_opt_passes.py +136 -0
  279. angr/analyses/deobfuscator/string_obf_peephole_optimizer.py +47 -0
  280. angr/analyses/disassembly.py +1351 -0
  281. angr/analyses/disassembly_utils.py +101 -0
  282. angr/analyses/dominance_frontier.py +57 -0
  283. angr/analyses/fcp/__init__.py +4 -0
  284. angr/analyses/fcp/fcp.py +427 -0
  285. angr/analyses/find_objects_static.py +205 -0
  286. angr/analyses/flirt/__init__.py +47 -0
  287. angr/analyses/flirt/consts.py +160 -0
  288. angr/analyses/flirt/flirt.py +249 -0
  289. angr/analyses/flirt/flirt_function.py +20 -0
  290. angr/analyses/flirt/flirt_matcher.py +352 -0
  291. angr/analyses/flirt/flirt_module.py +32 -0
  292. angr/analyses/flirt/flirt_node.py +23 -0
  293. angr/analyses/flirt/flirt_sig.py +359 -0
  294. angr/analyses/flirt/flirt_utils.py +31 -0
  295. angr/analyses/forward_analysis/__init__.py +12 -0
  296. angr/analyses/forward_analysis/forward_analysis.py +619 -0
  297. angr/analyses/forward_analysis/job_info.py +64 -0
  298. angr/analyses/forward_analysis/visitors/__init__.py +14 -0
  299. angr/analyses/forward_analysis/visitors/call_graph.py +29 -0
  300. angr/analyses/forward_analysis/visitors/function_graph.py +86 -0
  301. angr/analyses/forward_analysis/visitors/graph.py +242 -0
  302. angr/analyses/forward_analysis/visitors/loop.py +29 -0
  303. angr/analyses/forward_analysis/visitors/single_node_graph.py +38 -0
  304. angr/analyses/identifier/__init__.py +5 -0
  305. angr/analyses/identifier/custom_callable.py +137 -0
  306. angr/analyses/identifier/errors.py +10 -0
  307. angr/analyses/identifier/func.py +60 -0
  308. angr/analyses/identifier/functions/__init__.py +37 -0
  309. angr/analyses/identifier/functions/atoi.py +73 -0
  310. angr/analyses/identifier/functions/based_atoi.py +125 -0
  311. angr/analyses/identifier/functions/fdprintf.py +123 -0
  312. angr/analyses/identifier/functions/free.py +64 -0
  313. angr/analyses/identifier/functions/int2str.py +287 -0
  314. angr/analyses/identifier/functions/malloc.py +111 -0
  315. angr/analyses/identifier/functions/memcmp.py +67 -0
  316. angr/analyses/identifier/functions/memcpy.py +89 -0
  317. angr/analyses/identifier/functions/memset.py +43 -0
  318. angr/analyses/identifier/functions/printf.py +123 -0
  319. angr/analyses/identifier/functions/recv_until.py +312 -0
  320. angr/analyses/identifier/functions/skip_calloc.py +73 -0
  321. angr/analyses/identifier/functions/skip_realloc.py +97 -0
  322. angr/analyses/identifier/functions/skip_recv_n.py +105 -0
  323. angr/analyses/identifier/functions/snprintf.py +112 -0
  324. angr/analyses/identifier/functions/sprintf.py +116 -0
  325. angr/analyses/identifier/functions/strcasecmp.py +33 -0
  326. angr/analyses/identifier/functions/strcmp.py +113 -0
  327. angr/analyses/identifier/functions/strcpy.py +43 -0
  328. angr/analyses/identifier/functions/strlen.py +27 -0
  329. angr/analyses/identifier/functions/strncmp.py +104 -0
  330. angr/analyses/identifier/functions/strncpy.py +65 -0
  331. angr/analyses/identifier/functions/strtol.py +89 -0
  332. angr/analyses/identifier/identify.py +825 -0
  333. angr/analyses/identifier/runner.py +360 -0
  334. angr/analyses/init_finder.py +289 -0
  335. angr/analyses/loop_analysis/__init__.py +4 -0
  336. angr/analyses/loop_analysis/loop_analysis.py +464 -0
  337. angr/analyses/loop_analysis.py +349 -0
  338. angr/analyses/loop_unroller/__init__.py +4 -0
  339. angr/analyses/loop_unroller/loop_unroller.py +222 -0
  340. angr/analyses/loopfinder.py +171 -0
  341. angr/analyses/outliner/__init__.py +7 -0
  342. angr/analyses/outliner/outliner.py +402 -0
  343. angr/analyses/patchfinder.py +137 -0
  344. angr/analyses/pathfinder.py +282 -0
  345. angr/analyses/propagator/__init__.py +5 -0
  346. angr/analyses/propagator/engine_base.py +62 -0
  347. angr/analyses/propagator/engine_vex.py +297 -0
  348. angr/analyses/propagator/propagator.py +361 -0
  349. angr/analyses/propagator/top_checker_mixin.py +218 -0
  350. angr/analyses/propagator/values.py +117 -0
  351. angr/analyses/propagator/vex_vars.py +68 -0
  352. angr/analyses/proximity_graph.py +444 -0
  353. angr/analyses/purity/__init__.py +15 -0
  354. angr/analyses/purity/analysis.py +78 -0
  355. angr/analyses/purity/engine.py +593 -0
  356. angr/analyses/reaching_definitions/__init__.py +67 -0
  357. angr/analyses/reaching_definitions/call_trace.py +73 -0
  358. angr/analyses/reaching_definitions/dep_graph.py +433 -0
  359. angr/analyses/reaching_definitions/engine_ail.py +1128 -0
  360. angr/analyses/reaching_definitions/engine_vex.py +1128 -0
  361. angr/analyses/reaching_definitions/external_codeloc.py +0 -0
  362. angr/analyses/reaching_definitions/function_handler.py +639 -0
  363. angr/analyses/reaching_definitions/function_handler_library/__init__.py +12 -0
  364. angr/analyses/reaching_definitions/function_handler_library/stdio.py +269 -0
  365. angr/analyses/reaching_definitions/function_handler_library/stdlib.py +195 -0
  366. angr/analyses/reaching_definitions/function_handler_library/string.py +158 -0
  367. angr/analyses/reaching_definitions/function_handler_library/unistd.py +51 -0
  368. angr/analyses/reaching_definitions/heap_allocator.py +70 -0
  369. angr/analyses/reaching_definitions/rd_initializer.py +237 -0
  370. angr/analyses/reaching_definitions/rd_state.py +579 -0
  371. angr/analyses/reaching_definitions/reaching_definitions.py +581 -0
  372. angr/analyses/reaching_definitions/subject.py +65 -0
  373. angr/analyses/reassembler.py +2900 -0
  374. angr/analyses/s_liveness.py +254 -0
  375. angr/analyses/s_propagator.py +575 -0
  376. angr/analyses/s_reaching_definitions/__init__.py +12 -0
  377. angr/analyses/s_reaching_definitions/s_rda_model.py +145 -0
  378. angr/analyses/s_reaching_definitions/s_rda_view.py +344 -0
  379. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +230 -0
  380. angr/analyses/smc.py +160 -0
  381. angr/analyses/soot_class_hierarchy.py +273 -0
  382. angr/analyses/stack_pointer_tracker.py +954 -0
  383. angr/analyses/static_hooker.py +53 -0
  384. angr/analyses/typehoon/__init__.py +5 -0
  385. angr/analyses/typehoon/dfa.py +118 -0
  386. angr/analyses/typehoon/lifter.py +133 -0
  387. angr/analyses/typehoon/simple_solver.py +2009 -0
  388. angr/analyses/typehoon/translator.py +283 -0
  389. angr/analyses/typehoon/typeconsts.py +439 -0
  390. angr/analyses/typehoon/typehoon.py +338 -0
  391. angr/analyses/typehoon/typevars.py +633 -0
  392. angr/analyses/typehoon/variance.py +11 -0
  393. angr/analyses/unpacker/__init__.py +6 -0
  394. angr/analyses/unpacker/obfuscation_detector.py +103 -0
  395. angr/analyses/unpacker/packing_detector.py +138 -0
  396. angr/analyses/variable_recovery/__init__.py +9 -0
  397. angr/analyses/variable_recovery/annotations.py +58 -0
  398. angr/analyses/variable_recovery/engine_ail.py +978 -0
  399. angr/analyses/variable_recovery/engine_base.py +1256 -0
  400. angr/analyses/variable_recovery/engine_vex.py +594 -0
  401. angr/analyses/variable_recovery/irsb_scanner.py +143 -0
  402. angr/analyses/variable_recovery/variable_recovery.py +574 -0
  403. angr/analyses/variable_recovery/variable_recovery_base.py +489 -0
  404. angr/analyses/variable_recovery/variable_recovery_fast.py +669 -0
  405. angr/analyses/veritesting.py +626 -0
  406. angr/analyses/vfg.py +1898 -0
  407. angr/analyses/vsa_ddg.py +420 -0
  408. angr/analyses/vtable.py +92 -0
  409. angr/analyses/xrefs.py +286 -0
  410. angr/angrdb/__init__.py +14 -0
  411. angr/angrdb/db.py +215 -0
  412. angr/angrdb/models.py +184 -0
  413. angr/angrdb/serializers/__init__.py +10 -0
  414. angr/angrdb/serializers/cfg_model.py +41 -0
  415. angr/angrdb/serializers/comments.py +60 -0
  416. angr/angrdb/serializers/funcs.py +61 -0
  417. angr/angrdb/serializers/kb.py +111 -0
  418. angr/angrdb/serializers/labels.py +59 -0
  419. angr/angrdb/serializers/loader.py +165 -0
  420. angr/angrdb/serializers/structured_code.py +167 -0
  421. angr/angrdb/serializers/variables.py +58 -0
  422. angr/angrdb/serializers/xrefs.py +48 -0
  423. angr/annocfg.py +317 -0
  424. angr/blade.py +431 -0
  425. angr/block.py +509 -0
  426. angr/callable.py +176 -0
  427. angr/calling_conventions.py +2613 -0
  428. angr/code_location.py +249 -0
  429. angr/codenode.py +145 -0
  430. angr/concretization_strategies/__init__.py +32 -0
  431. angr/concretization_strategies/any.py +17 -0
  432. angr/concretization_strategies/any_named.py +35 -0
  433. angr/concretization_strategies/base.py +81 -0
  434. angr/concretization_strategies/controlled_data.py +58 -0
  435. angr/concretization_strategies/eval.py +19 -0
  436. angr/concretization_strategies/logging.py +35 -0
  437. angr/concretization_strategies/max.py +25 -0
  438. angr/concretization_strategies/nonzero.py +16 -0
  439. angr/concretization_strategies/nonzero_range.py +22 -0
  440. angr/concretization_strategies/norepeats.py +37 -0
  441. angr/concretization_strategies/norepeats_range.py +37 -0
  442. angr/concretization_strategies/range.py +19 -0
  443. angr/concretization_strategies/signed_add.py +31 -0
  444. angr/concretization_strategies/single.py +15 -0
  445. angr/concretization_strategies/solutions.py +20 -0
  446. angr/concretization_strategies/unlimited_range.py +17 -0
  447. angr/distributed/__init__.py +9 -0
  448. angr/distributed/server.py +197 -0
  449. angr/distributed/worker.py +185 -0
  450. angr/emulator.py +144 -0
  451. angr/engines/__init__.py +69 -0
  452. angr/engines/ail/__init__.py +16 -0
  453. angr/engines/ail/callstack.py +58 -0
  454. angr/engines/ail/engine_light.py +903 -0
  455. angr/engines/ail/engine_successors.py +24 -0
  456. angr/engines/ail/setup.py +57 -0
  457. angr/engines/concrete.py +66 -0
  458. angr/engines/engine.py +29 -0
  459. angr/engines/failure.py +27 -0
  460. angr/engines/hook.py +93 -0
  461. angr/engines/icicle.py +294 -0
  462. angr/engines/light/__init__.py +23 -0
  463. angr/engines/light/data.py +681 -0
  464. angr/engines/light/engine.py +1297 -0
  465. angr/engines/pcode/__init__.py +9 -0
  466. angr/engines/pcode/behavior.py +998 -0
  467. angr/engines/pcode/cc.py +148 -0
  468. angr/engines/pcode/emulate.py +440 -0
  469. angr/engines/pcode/engine.py +242 -0
  470. angr/engines/pcode/lifter.py +1428 -0
  471. angr/engines/procedure.py +70 -0
  472. angr/engines/soot/__init__.py +5 -0
  473. angr/engines/soot/engine.py +410 -0
  474. angr/engines/soot/exceptions.py +17 -0
  475. angr/engines/soot/expressions/__init__.py +87 -0
  476. angr/engines/soot/expressions/arrayref.py +22 -0
  477. angr/engines/soot/expressions/base.py +21 -0
  478. angr/engines/soot/expressions/binop.py +28 -0
  479. angr/engines/soot/expressions/cast.py +22 -0
  480. angr/engines/soot/expressions/condition.py +35 -0
  481. angr/engines/soot/expressions/constants.py +47 -0
  482. angr/engines/soot/expressions/instanceOf.py +15 -0
  483. angr/engines/soot/expressions/instancefieldref.py +8 -0
  484. angr/engines/soot/expressions/invoke.py +114 -0
  485. angr/engines/soot/expressions/length.py +8 -0
  486. angr/engines/soot/expressions/local.py +8 -0
  487. angr/engines/soot/expressions/new.py +16 -0
  488. angr/engines/soot/expressions/newArray.py +54 -0
  489. angr/engines/soot/expressions/newMultiArray.py +86 -0
  490. angr/engines/soot/expressions/paramref.py +8 -0
  491. angr/engines/soot/expressions/phi.py +30 -0
  492. angr/engines/soot/expressions/staticfieldref.py +8 -0
  493. angr/engines/soot/expressions/thisref.py +7 -0
  494. angr/engines/soot/expressions/unsupported.py +7 -0
  495. angr/engines/soot/field_dispatcher.py +46 -0
  496. angr/engines/soot/method_dispatcher.py +46 -0
  497. angr/engines/soot/statements/__init__.py +44 -0
  498. angr/engines/soot/statements/assign.py +30 -0
  499. angr/engines/soot/statements/base.py +79 -0
  500. angr/engines/soot/statements/goto.py +14 -0
  501. angr/engines/soot/statements/identity.py +15 -0
  502. angr/engines/soot/statements/if_.py +19 -0
  503. angr/engines/soot/statements/invoke.py +12 -0
  504. angr/engines/soot/statements/return_.py +20 -0
  505. angr/engines/soot/statements/switch.py +41 -0
  506. angr/engines/soot/statements/throw.py +15 -0
  507. angr/engines/soot/values/__init__.py +38 -0
  508. angr/engines/soot/values/arrayref.py +122 -0
  509. angr/engines/soot/values/base.py +7 -0
  510. angr/engines/soot/values/constants.py +18 -0
  511. angr/engines/soot/values/instancefieldref.py +44 -0
  512. angr/engines/soot/values/local.py +18 -0
  513. angr/engines/soot/values/paramref.py +18 -0
  514. angr/engines/soot/values/staticfieldref.py +38 -0
  515. angr/engines/soot/values/strref.py +38 -0
  516. angr/engines/soot/values/thisref.py +149 -0
  517. angr/engines/successors.py +608 -0
  518. angr/engines/syscall.py +51 -0
  519. angr/engines/unicorn.py +490 -0
  520. angr/engines/vex/__init__.py +20 -0
  521. angr/engines/vex/claripy/__init__.py +5 -0
  522. angr/engines/vex/claripy/ccall.py +2097 -0
  523. angr/engines/vex/claripy/datalayer.py +141 -0
  524. angr/engines/vex/claripy/irop.py +1276 -0
  525. angr/engines/vex/heavy/__init__.py +16 -0
  526. angr/engines/vex/heavy/actions.py +231 -0
  527. angr/engines/vex/heavy/concretizers.py +403 -0
  528. angr/engines/vex/heavy/dirty.py +466 -0
  529. angr/engines/vex/heavy/heavy.py +370 -0
  530. angr/engines/vex/heavy/inspect.py +52 -0
  531. angr/engines/vex/heavy/resilience.py +85 -0
  532. angr/engines/vex/heavy/super_fastpath.py +34 -0
  533. angr/engines/vex/lifter.py +420 -0
  534. angr/engines/vex/light/__init__.py +11 -0
  535. angr/engines/vex/light/light.py +551 -0
  536. angr/engines/vex/light/resilience.py +74 -0
  537. angr/engines/vex/light/slicing.py +52 -0
  538. angr/errors.py +611 -0
  539. angr/exploration_techniques/__init__.py +53 -0
  540. angr/exploration_techniques/base.py +126 -0
  541. angr/exploration_techniques/bucketizer.py +94 -0
  542. angr/exploration_techniques/common.py +56 -0
  543. angr/exploration_techniques/dfs.py +37 -0
  544. angr/exploration_techniques/director.py +520 -0
  545. angr/exploration_techniques/driller_core.py +100 -0
  546. angr/exploration_techniques/explorer.py +152 -0
  547. angr/exploration_techniques/lengthlimiter.py +22 -0
  548. angr/exploration_techniques/local_loop_seer.py +65 -0
  549. angr/exploration_techniques/loop_seer.py +236 -0
  550. angr/exploration_techniques/manual_mergepoint.py +82 -0
  551. angr/exploration_techniques/memory_watcher.py +43 -0
  552. angr/exploration_techniques/oppologist.py +92 -0
  553. angr/exploration_techniques/slicecutor.py +118 -0
  554. angr/exploration_techniques/spiller.py +280 -0
  555. angr/exploration_techniques/spiller_db.py +27 -0
  556. angr/exploration_techniques/stochastic.py +56 -0
  557. angr/exploration_techniques/stub_stasher.py +19 -0
  558. angr/exploration_techniques/suggestions.py +159 -0
  559. angr/exploration_techniques/tech_builder.py +49 -0
  560. angr/exploration_techniques/threading.py +69 -0
  561. angr/exploration_techniques/timeout.py +34 -0
  562. angr/exploration_techniques/tracer.py +1098 -0
  563. angr/exploration_techniques/unique.py +106 -0
  564. angr/exploration_techniques/veritesting.py +37 -0
  565. angr/factory.py +413 -0
  566. angr/flirt/__init__.py +124 -0
  567. angr/flirt/build_sig.py +305 -0
  568. angr/graph_utils.py +0 -0
  569. angr/keyed_region.py +525 -0
  570. angr/knowledge_base.py +146 -0
  571. angr/knowledge_plugins/__init__.py +43 -0
  572. angr/knowledge_plugins/callsite_prototypes.py +95 -0
  573. angr/knowledge_plugins/cfg/__init__.py +18 -0
  574. angr/knowledge_plugins/cfg/cfg_manager.py +95 -0
  575. angr/knowledge_plugins/cfg/cfg_model.py +1043 -0
  576. angr/knowledge_plugins/cfg/cfg_node.py +536 -0
  577. angr/knowledge_plugins/cfg/indirect_jump.py +131 -0
  578. angr/knowledge_plugins/cfg/memory_data.py +156 -0
  579. angr/knowledge_plugins/comments.py +16 -0
  580. angr/knowledge_plugins/custom_strings.py +38 -0
  581. angr/knowledge_plugins/data.py +22 -0
  582. angr/knowledge_plugins/debug_variables.py +216 -0
  583. angr/knowledge_plugins/functions/__init__.py +9 -0
  584. angr/knowledge_plugins/functions/function.py +1830 -0
  585. angr/knowledge_plugins/functions/function_manager.py +621 -0
  586. angr/knowledge_plugins/functions/function_parser.py +360 -0
  587. angr/knowledge_plugins/functions/soot_function.py +128 -0
  588. angr/knowledge_plugins/indirect_jumps.py +35 -0
  589. angr/knowledge_plugins/key_definitions/__init__.py +17 -0
  590. angr/knowledge_plugins/key_definitions/atoms.py +374 -0
  591. angr/knowledge_plugins/key_definitions/constants.py +29 -0
  592. angr/knowledge_plugins/key_definitions/definition.py +216 -0
  593. angr/knowledge_plugins/key_definitions/environment.py +96 -0
  594. angr/knowledge_plugins/key_definitions/heap_address.py +33 -0
  595. angr/knowledge_plugins/key_definitions/key_definition_manager.py +82 -0
  596. angr/knowledge_plugins/key_definitions/live_definitions.py +1020 -0
  597. angr/knowledge_plugins/key_definitions/liveness.py +165 -0
  598. angr/knowledge_plugins/key_definitions/rd_model.py +171 -0
  599. angr/knowledge_plugins/key_definitions/tag.py +78 -0
  600. angr/knowledge_plugins/key_definitions/undefined.py +70 -0
  601. angr/knowledge_plugins/key_definitions/unknown_size.py +86 -0
  602. angr/knowledge_plugins/key_definitions/uses.py +178 -0
  603. angr/knowledge_plugins/labels.py +110 -0
  604. angr/knowledge_plugins/obfuscations.py +40 -0
  605. angr/knowledge_plugins/patches.py +126 -0
  606. angr/knowledge_plugins/plugin.py +24 -0
  607. angr/knowledge_plugins/propagations/__init__.py +10 -0
  608. angr/knowledge_plugins/propagations/prop_value.py +191 -0
  609. angr/knowledge_plugins/propagations/propagation_manager.py +60 -0
  610. angr/knowledge_plugins/propagations/propagation_model.py +80 -0
  611. angr/knowledge_plugins/propagations/states.py +552 -0
  612. angr/knowledge_plugins/structured_code.py +63 -0
  613. angr/knowledge_plugins/types.py +95 -0
  614. angr/knowledge_plugins/variables/__init__.py +8 -0
  615. angr/knowledge_plugins/variables/variable_access.py +113 -0
  616. angr/knowledge_plugins/variables/variable_manager.py +1375 -0
  617. angr/knowledge_plugins/xrefs/__init__.py +12 -0
  618. angr/knowledge_plugins/xrefs/xref.py +150 -0
  619. angr/knowledge_plugins/xrefs/xref_manager.py +127 -0
  620. angr/knowledge_plugins/xrefs/xref_types.py +16 -0
  621. angr/misc/__init__.py +19 -0
  622. angr/misc/ansi.py +47 -0
  623. angr/misc/autoimport.py +90 -0
  624. angr/misc/bug_report.py +126 -0
  625. angr/misc/hookset.py +106 -0
  626. angr/misc/loggers.py +130 -0
  627. angr/misc/picklable_lock.py +46 -0
  628. angr/misc/plugins.py +289 -0
  629. angr/misc/telemetry.py +54 -0
  630. angr/misc/testing.py +24 -0
  631. angr/misc/ux.py +31 -0
  632. angr/procedures/__init__.py +12 -0
  633. angr/procedures/advapi32/__init__.py +0 -0
  634. angr/procedures/cgc/__init__.py +3 -0
  635. angr/procedures/cgc/_terminate.py +11 -0
  636. angr/procedures/cgc/allocate.py +75 -0
  637. angr/procedures/cgc/deallocate.py +67 -0
  638. angr/procedures/cgc/fdwait.py +65 -0
  639. angr/procedures/cgc/random.py +67 -0
  640. angr/procedures/cgc/receive.py +93 -0
  641. angr/procedures/cgc/transmit.py +65 -0
  642. angr/procedures/definitions/__init__.py +1043 -0
  643. angr/procedures/definitions/cgc.py +23 -0
  644. angr/procedures/definitions/common/glibc.json +3516 -0
  645. angr/procedures/definitions/gnulib.py +41 -0
  646. angr/procedures/definitions/libstdcpp.py +25 -0
  647. angr/procedures/definitions/linux_kernel.py +8382 -0
  648. angr/procedures/definitions/linux_loader.py +7 -0
  649. angr/procedures/definitions/macho_libsystem.py +18 -0
  650. angr/procedures/definitions/msvcr.py +25 -0
  651. angr/procedures/definitions/parse_glibc.py +77 -0
  652. angr/procedures/definitions/parse_syscalls_from_local_system.py +54 -0
  653. angr/procedures/definitions/parse_win32json.py +2540 -0
  654. angr/procedures/definitions/types_stl.py +22 -0
  655. angr/procedures/definitions/wdk/api-ms-win-dx-d3dkmt-l1-1-4.json +24 -0
  656. angr/procedures/definitions/wdk/api-ms-win-dx-d3dkmt-l1-1-6.json +18 -0
  657. angr/procedures/definitions/wdk/clfs.json +189 -0
  658. angr/procedures/definitions/wdk/fltmgr.json +813 -0
  659. angr/procedures/definitions/wdk/fwpkclnt.json +24 -0
  660. angr/procedures/definitions/wdk/fwpuclnt.json +453 -0
  661. angr/procedures/definitions/wdk/gdi32.json +528 -0
  662. angr/procedures/definitions/wdk/hal.json +96 -0
  663. angr/procedures/definitions/wdk/ksecdd.json +72 -0
  664. angr/procedures/definitions/wdk/ndis.json +336 -0
  665. angr/procedures/definitions/wdk/ntoskrnl.json +5158 -0
  666. angr/procedures/definitions/wdk/offreg.json +87 -0
  667. angr/procedures/definitions/wdk/pshed.json +33 -0
  668. angr/procedures/definitions/wdk/secur32.json +39 -0
  669. angr/procedures/definitions/wdk/vhfum.json +30 -0
  670. angr/procedures/definitions/win32/_types_win32.json +34480 -0
  671. angr/procedures/definitions/win32/aclui.json +24 -0
  672. angr/procedures/definitions/win32/activeds.json +81 -0
  673. angr/procedures/definitions/win32/advapi32.json +2505 -0
  674. angr/procedures/definitions/win32/advpack.json +165 -0
  675. angr/procedures/definitions/win32/amsi.json +36 -0
  676. angr/procedures/definitions/win32/api-ms-win-appmodel-runtime-l1-1-1.json +45 -0
  677. angr/procedures/definitions/win32/api-ms-win-appmodel-runtime-l1-1-3.json +30 -0
  678. angr/procedures/definitions/win32/api-ms-win-appmodel-runtime-l1-1-6.json +18 -0
  679. angr/procedures/definitions/win32/api-ms-win-core-apiquery-l2-1-0.json +18 -0
  680. angr/procedures/definitions/win32/api-ms-win-core-backgroundtask-l1-1-0.json +18 -0
  681. angr/procedures/definitions/win32/api-ms-win-core-comm-l1-1-1.json +18 -0
  682. angr/procedures/definitions/win32/api-ms-win-core-comm-l1-1-2.json +18 -0
  683. angr/procedures/definitions/win32/api-ms-win-core-enclave-l1-1-1.json +24 -0
  684. angr/procedures/definitions/win32/api-ms-win-core-errorhandling-l1-1-3.json +18 -0
  685. angr/procedures/definitions/win32/api-ms-win-core-featurestaging-l1-1-0.json +30 -0
  686. angr/procedures/definitions/win32/api-ms-win-core-featurestaging-l1-1-1.json +18 -0
  687. angr/procedures/definitions/win32/api-ms-win-core-file-fromapp-l1-1-0.json +48 -0
  688. angr/procedures/definitions/win32/api-ms-win-core-handle-l1-1-0.json +18 -0
  689. angr/procedures/definitions/win32/api-ms-win-core-ioring-l1-1-0.json +51 -0
  690. angr/procedures/definitions/win32/api-ms-win-core-marshal-l1-1-0.json +27 -0
  691. angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-3.json +27 -0
  692. angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-4.json +18 -0
  693. angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-5.json +24 -0
  694. angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-6.json +27 -0
  695. angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-7.json +21 -0
  696. angr/procedures/definitions/win32/api-ms-win-core-memory-l1-1-8.json +24 -0
  697. angr/procedures/definitions/win32/api-ms-win-core-path-l1-1-0.json +81 -0
  698. angr/procedures/definitions/win32/api-ms-win-core-psm-appnotify-l1-1-0.json +21 -0
  699. angr/procedures/definitions/win32/api-ms-win-core-psm-appnotify-l1-1-1.json +21 -0
  700. angr/procedures/definitions/win32/api-ms-win-core-realtime-l1-1-1.json +24 -0
  701. angr/procedures/definitions/win32/api-ms-win-core-realtime-l1-1-2.json +24 -0
  702. angr/procedures/definitions/win32/api-ms-win-core-slapi-l1-1-0.json +18 -0
  703. angr/procedures/definitions/win32/api-ms-win-core-state-helpers-l1-1-0.json +18 -0
  704. angr/procedures/definitions/win32/api-ms-win-core-synch-l1-2-0.json +24 -0
  705. angr/procedures/definitions/win32/api-ms-win-core-sysinfo-l1-2-0.json +18 -0
  706. angr/procedures/definitions/win32/api-ms-win-core-sysinfo-l1-2-3.json +21 -0
  707. angr/procedures/definitions/win32/api-ms-win-core-sysinfo-l1-2-4.json +21 -0
  708. angr/procedures/definitions/win32/api-ms-win-core-sysinfo-l1-2-6.json +18 -0
  709. angr/procedures/definitions/win32/api-ms-win-core-util-l1-1-1.json +21 -0
  710. angr/procedures/definitions/win32/api-ms-win-core-wow64-l1-1-1.json +24 -0
  711. angr/procedures/definitions/win32/api-ms-win-devices-query-l1-1-0.json +42 -0
  712. angr/procedures/definitions/win32/api-ms-win-devices-query-l1-1-1.json +30 -0
  713. angr/procedures/definitions/win32/api-ms-win-dx-d3dkmt-l1-1-0.json +18 -0
  714. angr/procedures/definitions/win32/api-ms-win-gaming-deviceinformation-l1-1-0.json +18 -0
  715. angr/procedures/definitions/win32/api-ms-win-gaming-expandedresources-l1-1-0.json +24 -0
  716. angr/procedures/definitions/win32/api-ms-win-gaming-tcui-l1-1-0.json +36 -0
  717. angr/procedures/definitions/win32/api-ms-win-gaming-tcui-l1-1-1.json +21 -0
  718. angr/procedures/definitions/win32/api-ms-win-gaming-tcui-l1-1-2.json +36 -0
  719. angr/procedures/definitions/win32/api-ms-win-gaming-tcui-l1-1-3.json +21 -0
  720. angr/procedures/definitions/win32/api-ms-win-gaming-tcui-l1-1-4.json +39 -0
  721. angr/procedures/definitions/win32/api-ms-win-mm-misc-l1-1-1.json +18 -0
  722. angr/procedures/definitions/win32/api-ms-win-net-isolation-l1-1-0.json +39 -0
  723. angr/procedures/definitions/win32/api-ms-win-security-base-l1-2-2.json +18 -0
  724. angr/procedures/definitions/win32/api-ms-win-security-isolatedcontainer-l1-1-0.json +18 -0
  725. angr/procedures/definitions/win32/api-ms-win-security-isolatedcontainer-l1-1-1.json +18 -0
  726. angr/procedures/definitions/win32/api-ms-win-service-core-l1-1-3.json +18 -0
  727. angr/procedures/definitions/win32/api-ms-win-service-core-l1-1-4.json +18 -0
  728. angr/procedures/definitions/win32/api-ms-win-service-core-l1-1-5.json +21 -0
  729. angr/procedures/definitions/win32/api-ms-win-shcore-scaling-l1-1-0.json +24 -0
  730. angr/procedures/definitions/win32/api-ms-win-shcore-scaling-l1-1-1.json +33 -0
  731. angr/procedures/definitions/win32/api-ms-win-shcore-scaling-l1-1-2.json +18 -0
  732. angr/procedures/definitions/win32/api-ms-win-wsl-api-l1-1-0.json +36 -0
  733. angr/procedures/definitions/win32/apphelp.json +18 -0
  734. angr/procedures/definitions/win32/authz.json +114 -0
  735. angr/procedures/definitions/win32/avicap32.json +27 -0
  736. angr/procedures/definitions/win32/avifil32.json +195 -0
  737. angr/procedures/definitions/win32/avrt.json +57 -0
  738. angr/procedures/definitions/win32/bcp47mrm.json +21 -0
  739. angr/procedures/definitions/win32/bcrypt.json +174 -0
  740. angr/procedures/definitions/win32/bcryptprimitives.json +21 -0
  741. angr/procedures/definitions/win32/bluetoothapis.json +138 -0
  742. angr/procedures/definitions/win32/bthprops_cpl.json +33 -0
  743. angr/procedures/definitions/win32/cabinet.json +81 -0
  744. angr/procedures/definitions/win32/certadm.json +69 -0
  745. angr/procedures/definitions/win32/certpoleng.json +39 -0
  746. angr/procedures/definitions/win32/cfgmgr32.json +732 -0
  747. angr/procedures/definitions/win32/chakra.json +270 -0
  748. angr/procedures/definitions/win32/cldapi.json +123 -0
  749. angr/procedures/definitions/win32/clfsw32.json +192 -0
  750. angr/procedures/definitions/win32/clusapi.json +855 -0
  751. angr/procedures/definitions/win32/comctl32.json +360 -0
  752. angr/procedures/definitions/win32/comdlg32.json +78 -0
  753. angr/procedures/definitions/win32/compstui.json +27 -0
  754. angr/procedures/definitions/win32/computecore.json +177 -0
  755. angr/procedures/definitions/win32/computenetwork.json +144 -0
  756. angr/procedures/definitions/win32/computestorage.json +51 -0
  757. angr/procedures/definitions/win32/comsvcs.json +36 -0
  758. angr/procedures/definitions/win32/credui.json +72 -0
  759. angr/procedures/definitions/win32/crypt32.json +702 -0
  760. angr/procedures/definitions/win32/cryptnet.json +30 -0
  761. angr/procedures/definitions/win32/cryptui.json +45 -0
  762. angr/procedures/definitions/win32/cryptxml.json +72 -0
  763. angr/procedures/definitions/win32/cscapi.json +27 -0
  764. angr/procedures/definitions/win32/d2d1.json +54 -0
  765. angr/procedures/definitions/win32/d3d10.json +96 -0
  766. angr/procedures/definitions/win32/d3d10_1.json +21 -0
  767. angr/procedures/definitions/win32/d3d11.json +24 -0
  768. angr/procedures/definitions/win32/d3d12.json +39 -0
  769. angr/procedures/definitions/win32/d3d9.json +48 -0
  770. angr/procedures/definitions/win32/d3dcompiler_47.json +93 -0
  771. angr/procedures/definitions/win32/d3dcsx.json +42 -0
  772. angr/procedures/definitions/win32/davclnt.json +69 -0
  773. angr/procedures/definitions/win32/dbgeng.json +27 -0
  774. angr/procedures/definitions/win32/dbghelp.json +663 -0
  775. angr/procedures/definitions/win32/dbgmodel.json +18 -0
  776. angr/procedures/definitions/win32/dciman32.json +75 -0
  777. angr/procedures/definitions/win32/dcomp.json +51 -0
  778. angr/procedures/definitions/win32/ddraw.json +36 -0
  779. angr/procedures/definitions/win32/deviceaccess.json +18 -0
  780. angr/procedures/definitions/win32/dflayout.json +18 -0
  781. angr/procedures/definitions/win32/dhcpcsvc.json +60 -0
  782. angr/procedures/definitions/win32/dhcpcsvc6.json +33 -0
  783. angr/procedures/definitions/win32/dhcpsapi.json +603 -0
  784. angr/procedures/definitions/win32/diagnosticdataquery.json +120 -0
  785. angr/procedures/definitions/win32/dinput8.json +18 -0
  786. angr/procedures/definitions/win32/directml.json +21 -0
  787. angr/procedures/definitions/win32/dmprocessxmlfiltered.json +18 -0
  788. angr/procedures/definitions/win32/dnsapi.json +207 -0
  789. angr/procedures/definitions/win32/drt.json +63 -0
  790. angr/procedures/definitions/win32/drtprov.json +42 -0
  791. angr/procedures/definitions/win32/drttransport.json +21 -0
  792. angr/procedures/definitions/win32/dsound.json +45 -0
  793. angr/procedures/definitions/win32/dsparse.json +72 -0
  794. angr/procedures/definitions/win32/dsprop.json +36 -0
  795. angr/procedures/definitions/win32/dssec.json +27 -0
  796. angr/procedures/definitions/win32/dsuiext.json +27 -0
  797. angr/procedures/definitions/win32/dwmapi.json +108 -0
  798. angr/procedures/definitions/win32/dwrite.json +18 -0
  799. angr/procedures/definitions/win32/dxcompiler.json +21 -0
  800. angr/procedures/definitions/win32/dxcore.json +18 -0
  801. angr/procedures/definitions/win32/dxgi.json +33 -0
  802. angr/procedures/definitions/win32/dxva2.json +129 -0
  803. angr/procedures/definitions/win32/eappcfg.json +57 -0
  804. angr/procedures/definitions/win32/eappprxy.json +69 -0
  805. angr/procedures/definitions/win32/efswrt.json +21 -0
  806. angr/procedures/definitions/win32/elscore.json +30 -0
  807. angr/procedures/definitions/win32/esent.json +702 -0
  808. angr/procedures/definitions/win32/evr.json +36 -0
  809. angr/procedures/definitions/win32/faultrep.json +27 -0
  810. angr/procedures/definitions/win32/fhsvcctl.json +36 -0
  811. angr/procedures/definitions/win32/firewallapi.json +24 -0
  812. angr/procedures/definitions/win32/fltlib.json +99 -0
  813. angr/procedures/definitions/win32/fontsub.json +21 -0
  814. angr/procedures/definitions/win32/forceinline.json +24 -0
  815. angr/procedures/definitions/win32/fwpuclnt.json +591 -0
  816. angr/procedures/definitions/win32/fxsutility.json +21 -0
  817. angr/procedures/definitions/win32/gdi32.json +1308 -0
  818. angr/procedures/definitions/win32/gdiplus.json +1902 -0
  819. angr/procedures/definitions/win32/glu32.json +171 -0
  820. angr/procedures/definitions/win32/gpedit.json +33 -0
  821. angr/procedures/definitions/win32/hhctrl_ocx.json +21 -0
  822. angr/procedures/definitions/win32/hid.json +150 -0
  823. angr/procedures/definitions/win32/hlink.json +99 -0
  824. angr/procedures/definitions/win32/hrtfapo.json +18 -0
  825. angr/procedures/definitions/win32/httpapi.json +144 -0
  826. angr/procedures/definitions/win32/icm32.json +78 -0
  827. angr/procedures/definitions/win32/icmui.json +21 -0
  828. angr/procedures/definitions/win32/icu.json +3090 -0
  829. angr/procedures/definitions/win32/ieframe.json +102 -0
  830. angr/procedures/definitions/win32/imagehlp.json +84 -0
  831. angr/procedures/definitions/win32/imgutil.json +42 -0
  832. angr/procedures/definitions/win32/imm32.json +261 -0
  833. angr/procedures/definitions/win32/infocardapi.json +66 -0
  834. angr/procedures/definitions/win32/inkobjcore.json +96 -0
  835. angr/procedures/definitions/win32/iphlpapi.json +618 -0
  836. angr/procedures/definitions/win32/iscsidsc.json +252 -0
  837. angr/procedures/definitions/win32/isolatedwindowsenvironmentutils.json +21 -0
  838. angr/procedures/definitions/win32/kernel32.json +4566 -0
  839. angr/procedures/definitions/win32/kernelbase.json +33 -0
  840. angr/procedures/definitions/win32/keycredmgr.json +27 -0
  841. angr/procedures/definitions/win32/ksproxy_ax.json +33 -0
  842. angr/procedures/definitions/win32/ksuser.json +39 -0
  843. angr/procedures/definitions/win32/ktmw32.json +132 -0
  844. angr/procedures/definitions/win32/licenseprotection.json +21 -0
  845. angr/procedures/definitions/win32/loadperf.json +51 -0
  846. angr/procedures/definitions/win32/magnification.json +72 -0
  847. angr/procedures/definitions/win32/mapi32.json +213 -0
  848. angr/procedures/definitions/win32/mdmlocalmanagement.json +24 -0
  849. angr/procedures/definitions/win32/mdmregistration.json +60 -0
  850. angr/procedures/definitions/win32/mf.json +201 -0
  851. angr/procedures/definitions/win32/mfcore.json +21 -0
  852. angr/procedures/definitions/win32/mfplat.json +450 -0
  853. angr/procedures/definitions/win32/mfplay.json +18 -0
  854. angr/procedures/definitions/win32/mfreadwrite.json +30 -0
  855. angr/procedures/definitions/win32/mfsensorgroup.json +45 -0
  856. angr/procedures/definitions/win32/mfsrcsnk.json +21 -0
  857. angr/procedures/definitions/win32/mgmtapi.json +42 -0
  858. angr/procedures/definitions/win32/mi.json +18 -0
  859. angr/procedures/definitions/win32/mmdevapi.json +18 -0
  860. angr/procedures/definitions/win32/mpr.json +156 -0
  861. angr/procedures/definitions/win32/mprapi.json +351 -0
  862. angr/procedures/definitions/win32/mqrt.json +117 -0
  863. angr/procedures/definitions/win32/mrmsupport.json +96 -0
  864. angr/procedures/definitions/win32/msacm32.json +141 -0
  865. angr/procedures/definitions/win32/msajapi.json +1656 -0
  866. angr/procedures/definitions/win32/mscms.json +252 -0
  867. angr/procedures/definitions/win32/mscoree.json +96 -0
  868. angr/procedures/definitions/win32/msctfmonitor.json +24 -0
  869. angr/procedures/definitions/win32/msdelta.json +63 -0
  870. angr/procedures/definitions/win32/msdmo.json +48 -0
  871. angr/procedures/definitions/win32/msdrm.json +267 -0
  872. angr/procedures/definitions/win32/msi.json +807 -0
  873. angr/procedures/definitions/win32/msimg32.json +24 -0
  874. angr/procedures/definitions/win32/mspatcha.json +63 -0
  875. angr/procedures/definitions/win32/mspatchc.json +42 -0
  876. angr/procedures/definitions/win32/msports.json +36 -0
  877. angr/procedures/definitions/win32/msrating.json +72 -0
  878. angr/procedures/definitions/win32/mssign32.json +45 -0
  879. angr/procedures/definitions/win32/mstask.json +21 -0
  880. angr/procedures/definitions/win32/msvfw32.json +144 -0
  881. angr/procedures/definitions/win32/mswsock.json +63 -0
  882. angr/procedures/definitions/win32/mtxdm.json +18 -0
  883. angr/procedures/definitions/win32/ncrypt.json +132 -0
  884. angr/procedures/definitions/win32/ndfapi.json +63 -0
  885. angr/procedures/definitions/win32/netapi32.json +633 -0
  886. angr/procedures/definitions/win32/netsh.json +39 -0
  887. angr/procedures/definitions/win32/netshell.json +21 -0
  888. angr/procedures/definitions/win32/newdev.json +48 -0
  889. angr/procedures/definitions/win32/ninput.json +105 -0
  890. angr/procedures/definitions/win32/normaliz.json +21 -0
  891. angr/procedures/definitions/win32/ntdll.json +234 -0
  892. angr/procedures/definitions/win32/ntdllk.json +18 -0
  893. angr/procedures/definitions/win32/ntdsapi.json +258 -0
  894. angr/procedures/definitions/win32/ntlanman.json +45 -0
  895. angr/procedures/definitions/win32/odbc32.json +477 -0
  896. angr/procedures/definitions/win32/odbcbcp.json +96 -0
  897. angr/procedures/definitions/win32/ole32.json +966 -0
  898. angr/procedures/definitions/win32/oleacc.json +66 -0
  899. angr/procedures/definitions/win32/oleaut32.json +1230 -0
  900. angr/procedures/definitions/win32/oledlg.json +84 -0
  901. angr/procedures/definitions/win32/ondemandconnroutehelper.json +30 -0
  902. angr/procedures/definitions/win32/opengl32.json +1080 -0
  903. angr/procedures/definitions/win32/opmxbox.json +24 -0
  904. angr/procedures/definitions/win32/p2p.json +339 -0
  905. angr/procedures/definitions/win32/p2pgraph.json +126 -0
  906. angr/procedures/definitions/win32/pdh.json +309 -0
  907. angr/procedures/definitions/win32/peerdist.json +99 -0
  908. angr/procedures/definitions/win32/powrprof.json +267 -0
  909. angr/procedures/definitions/win32/prntvpt.json +48 -0
  910. angr/procedures/definitions/win32/projectedfslib.json +72 -0
  911. angr/procedures/definitions/win32/propsys.json +669 -0
  912. angr/procedures/definitions/win32/psapi.json +96 -0
  913. angr/procedures/definitions/win32/quartz.json +21 -0
  914. angr/procedures/definitions/win32/query.json +27 -0
  915. angr/procedures/definitions/win32/qwave.json +48 -0
  916. angr/procedures/definitions/win32/rasapi32.json +267 -0
  917. angr/procedures/definitions/win32/rasdlg.json +33 -0
  918. angr/procedures/definitions/win32/resutils.json +375 -0
  919. angr/procedures/definitions/win32/rpcns4.json +198 -0
  920. angr/procedures/definitions/win32/rpcproxy.json +27 -0
  921. angr/procedures/definitions/win32/rpcrt4.json +1356 -0
  922. angr/procedures/definitions/win32/rstrtmgr.json +48 -0
  923. angr/procedures/definitions/win32/rtm.json +243 -0
  924. angr/procedures/definitions/win32/rtutils.json +138 -0
  925. angr/procedures/definitions/win32/rtworkq.json +114 -0
  926. angr/procedures/definitions/win32/sas.json +18 -0
  927. angr/procedures/definitions/win32/scarddlg.json +30 -0
  928. angr/procedures/definitions/win32/schannel.json +42 -0
  929. angr/procedures/definitions/win32/sechost.json +21 -0
  930. angr/procedures/definitions/win32/secur32.json +282 -0
  931. angr/procedures/definitions/win32/sensapi.json +24 -0
  932. angr/procedures/definitions/win32/sensorsutilsv2.json +135 -0
  933. angr/procedures/definitions/win32/setupapi.json +1017 -0
  934. angr/procedures/definitions/win32/sfc.json +33 -0
  935. angr/procedures/definitions/win32/shdocvw.json +24 -0
  936. angr/procedures/definitions/win32/shell32.json +747 -0
  937. angr/procedures/definitions/win32/shlwapi.json +1095 -0
  938. angr/procedures/definitions/win32/slc.json +111 -0
  939. angr/procedures/definitions/win32/slcext.json +27 -0
  940. angr/procedures/definitions/win32/slwga.json +18 -0
  941. angr/procedures/definitions/win32/snmpapi.json +93 -0
  942. angr/procedures/definitions/win32/spoolss.json +93 -0
  943. angr/procedures/definitions/win32/srclient.json +18 -0
  944. angr/procedures/definitions/win32/srpapi.json +48 -0
  945. angr/procedures/definitions/win32/sspicli.json +36 -0
  946. angr/procedures/definitions/win32/sti.json +18 -0
  947. angr/procedures/definitions/win32/t2embed.json +57 -0
  948. angr/procedures/definitions/win32/tapi32.json +762 -0
  949. angr/procedures/definitions/win32/tbs.json +57 -0
  950. angr/procedures/definitions/win32/tdh.json +96 -0
  951. angr/procedures/definitions/win32/tokenbinding.json +45 -0
  952. angr/procedures/definitions/win32/traffic.json +75 -0
  953. angr/procedures/definitions/win32/txfw32.json +42 -0
  954. angr/procedures/definitions/win32/ualapi.json +27 -0
  955. angr/procedures/definitions/win32/uiautomationcore.json +309 -0
  956. angr/procedures/definitions/win32/urlmon.json +246 -0
  957. angr/procedures/definitions/win32/user32.json +2298 -0
  958. angr/procedures/definitions/win32/userenv.json +147 -0
  959. angr/procedures/definitions/win32/usp10.json +135 -0
  960. angr/procedures/definitions/win32/uxtheme.json +246 -0
  961. angr/procedures/definitions/win32/verifier.json +18 -0
  962. angr/procedures/definitions/win32/version.json +57 -0
  963. angr/procedures/definitions/win32/vertdll.json +36 -0
  964. angr/procedures/definitions/win32/virtdisk.json +102 -0
  965. angr/procedures/definitions/win32/vmdevicehost.json +54 -0
  966. angr/procedures/definitions/win32/vmsavedstatedumpprovider.json +144 -0
  967. angr/procedures/definitions/win32/vssapi.json +18 -0
  968. angr/procedures/definitions/win32/wcmapi.json +30 -0
  969. angr/procedures/definitions/win32/wdsbp.json +36 -0
  970. angr/procedures/definitions/win32/wdsclientapi.json +126 -0
  971. angr/procedures/definitions/win32/wdsmc.json +33 -0
  972. angr/procedures/definitions/win32/wdspxe.json +108 -0
  973. angr/procedures/definitions/win32/wdstptc.json +54 -0
  974. angr/procedures/definitions/win32/webauthn.json +54 -0
  975. angr/procedures/definitions/win32/webservices.json +594 -0
  976. angr/procedures/definitions/win32/websocket.json +54 -0
  977. angr/procedures/definitions/win32/wecapi.json +60 -0
  978. angr/procedures/definitions/win32/wer.json +78 -0
  979. angr/procedures/definitions/win32/wevtapi.json +120 -0
  980. angr/procedures/definitions/win32/winbio.json +177 -0
  981. angr/procedures/definitions/win32/windows_ai_machinelearning.json +18 -0
  982. angr/procedures/definitions/win32/windows_media_mediacontrol.json +39 -0
  983. angr/procedures/definitions/win32/windows_networking.json +18 -0
  984. angr/procedures/definitions/win32/windows_ui_xaml.json +21 -0
  985. angr/procedures/definitions/win32/windowscodecs.json +42 -0
  986. angr/procedures/definitions/win32/winfax.json +183 -0
  987. angr/procedures/definitions/win32/winhttp.json +183 -0
  988. angr/procedures/definitions/win32/winhvemulation.json +27 -0
  989. angr/procedures/definitions/win32/winhvplatform.json +213 -0
  990. angr/procedures/definitions/win32/wininet.json +903 -0
  991. angr/procedures/definitions/win32/winml.json +18 -0
  992. angr/procedures/definitions/win32/winmm.json +543 -0
  993. angr/procedures/definitions/win32/winscard.json +225 -0
  994. angr/procedures/definitions/win32/winspool_drv.json +531 -0
  995. angr/procedures/definitions/win32/wintrust.json +195 -0
  996. angr/procedures/definitions/win32/winusb.json +117 -0
  997. angr/procedures/definitions/win32/wlanapi.json +195 -0
  998. angr/procedures/definitions/win32/wlanui.json +18 -0
  999. angr/procedures/definitions/win32/wldap32.json +744 -0
  1000. angr/procedures/definitions/win32/wldp.json +42 -0
  1001. angr/procedures/definitions/win32/wmvcore.json +48 -0
  1002. angr/procedures/definitions/win32/wnvapi.json +21 -0
  1003. angr/procedures/definitions/win32/wofutil.json +48 -0
  1004. angr/procedures/definitions/win32/ws2_32.json +495 -0
  1005. angr/procedures/definitions/win32/wscapi.json +33 -0
  1006. angr/procedures/definitions/win32/wsclient.json +24 -0
  1007. angr/procedures/definitions/win32/wsdapi.json +111 -0
  1008. angr/procedures/definitions/win32/wsmsvc.json +114 -0
  1009. angr/procedures/definitions/win32/wsnmp32.json +162 -0
  1010. angr/procedures/definitions/win32/wtsapi32.json +204 -0
  1011. angr/procedures/definitions/win32/xaudio2_8.json +27 -0
  1012. angr/procedures/definitions/win32/xinput1_4.json +36 -0
  1013. angr/procedures/definitions/win32/xmllite.json +33 -0
  1014. angr/procedures/definitions/win32/xolehlp.json +27 -0
  1015. angr/procedures/definitions/win32/xpsprint.json +21 -0
  1016. angr/procedures/glibc/__ctype_b_loc.py +21 -0
  1017. angr/procedures/glibc/__ctype_tolower_loc.py +21 -0
  1018. angr/procedures/glibc/__ctype_toupper_loc.py +21 -0
  1019. angr/procedures/glibc/__errno_location.py +7 -0
  1020. angr/procedures/glibc/__init__.py +3 -0
  1021. angr/procedures/glibc/__libc_init.py +37 -0
  1022. angr/procedures/glibc/__libc_start_main.py +301 -0
  1023. angr/procedures/glibc/dynamic_loading.py +20 -0
  1024. angr/procedures/glibc/scanf.py +19 -0
  1025. angr/procedures/glibc/sscanf.py +10 -0
  1026. angr/procedures/gnulib/__init__.py +3 -0
  1027. angr/procedures/gnulib/xalloc_die.py +14 -0
  1028. angr/procedures/gnulib/xstrtol_fatal.py +14 -0
  1029. angr/procedures/java/__init__.py +42 -0
  1030. angr/procedures/java/unconstrained.py +65 -0
  1031. angr/procedures/java_io/__init__.py +0 -0
  1032. angr/procedures/java_io/read.py +12 -0
  1033. angr/procedures/java_io/write.py +17 -0
  1034. angr/procedures/java_jni/__init__.py +482 -0
  1035. angr/procedures/java_jni/array_operations.py +312 -0
  1036. angr/procedures/java_jni/class_and_interface_operations.py +31 -0
  1037. angr/procedures/java_jni/field_access.py +173 -0
  1038. angr/procedures/java_jni/global_and_local_refs.py +57 -0
  1039. angr/procedures/java_jni/method_calls.py +365 -0
  1040. angr/procedures/java_jni/not_implemented.py +26 -0
  1041. angr/procedures/java_jni/object_operations.py +94 -0
  1042. angr/procedures/java_jni/string_operations.py +87 -0
  1043. angr/procedures/java_jni/version_information.py +12 -0
  1044. angr/procedures/java_lang/__init__.py +0 -0
  1045. angr/procedures/java_lang/character.py +30 -0
  1046. angr/procedures/java_lang/double.py +24 -0
  1047. angr/procedures/java_lang/exit.py +13 -0
  1048. angr/procedures/java_lang/getsimplename.py +18 -0
  1049. angr/procedures/java_lang/integer.py +43 -0
  1050. angr/procedures/java_lang/load_library.py +9 -0
  1051. angr/procedures/java_lang/math.py +15 -0
  1052. angr/procedures/java_lang/string.py +78 -0
  1053. angr/procedures/java_lang/stringbuilder.py +44 -0
  1054. angr/procedures/java_lang/system.py +18 -0
  1055. angr/procedures/java_util/__init__.py +0 -0
  1056. angr/procedures/java_util/collection.py +35 -0
  1057. angr/procedures/java_util/iterator.py +46 -0
  1058. angr/procedures/java_util/list.py +99 -0
  1059. angr/procedures/java_util/map.py +131 -0
  1060. angr/procedures/java_util/random.py +14 -0
  1061. angr/procedures/java_util/scanner_nextline.py +23 -0
  1062. angr/procedures/libc/__init__.py +3 -0
  1063. angr/procedures/libc/abort.py +9 -0
  1064. angr/procedures/libc/access.py +13 -0
  1065. angr/procedures/libc/atoi.py +14 -0
  1066. angr/procedures/libc/atol.py +13 -0
  1067. angr/procedures/libc/calloc.py +8 -0
  1068. angr/procedures/libc/closelog.py +10 -0
  1069. angr/procedures/libc/err.py +14 -0
  1070. angr/procedures/libc/error.py +54 -0
  1071. angr/procedures/libc/exit.py +11 -0
  1072. angr/procedures/libc/fclose.py +19 -0
  1073. angr/procedures/libc/feof.py +21 -0
  1074. angr/procedures/libc/fflush.py +16 -0
  1075. angr/procedures/libc/fgetc.py +27 -0
  1076. angr/procedures/libc/fgets.py +69 -0
  1077. angr/procedures/libc/fopen.py +63 -0
  1078. angr/procedures/libc/fprintf.py +25 -0
  1079. angr/procedures/libc/fputc.py +23 -0
  1080. angr/procedures/libc/fputs.py +24 -0
  1081. angr/procedures/libc/fread.py +24 -0
  1082. angr/procedures/libc/free.py +9 -0
  1083. angr/procedures/libc/fscanf.py +20 -0
  1084. angr/procedures/libc/fseek.py +34 -0
  1085. angr/procedures/libc/ftell.py +22 -0
  1086. angr/procedures/libc/fwrite.py +19 -0
  1087. angr/procedures/libc/getchar.py +13 -0
  1088. angr/procedures/libc/getdelim.py +99 -0
  1089. angr/procedures/libc/getegid.py +8 -0
  1090. angr/procedures/libc/geteuid.py +8 -0
  1091. angr/procedures/libc/getgid.py +8 -0
  1092. angr/procedures/libc/gets.py +68 -0
  1093. angr/procedures/libc/getuid.py +8 -0
  1094. angr/procedures/libc/malloc.py +12 -0
  1095. angr/procedures/libc/memcmp.py +69 -0
  1096. angr/procedures/libc/memcpy.py +45 -0
  1097. angr/procedures/libc/memset.py +72 -0
  1098. angr/procedures/libc/openlog.py +10 -0
  1099. angr/procedures/libc/perror.py +13 -0
  1100. angr/procedures/libc/printf.py +34 -0
  1101. angr/procedures/libc/putchar.py +13 -0
  1102. angr/procedures/libc/puts.py +19 -0
  1103. angr/procedures/libc/rand.py +8 -0
  1104. angr/procedures/libc/realloc.py +8 -0
  1105. angr/procedures/libc/rewind.py +12 -0
  1106. angr/procedures/libc/scanf.py +20 -0
  1107. angr/procedures/libc/setbuf.py +9 -0
  1108. angr/procedures/libc/setvbuf.py +7 -0
  1109. angr/procedures/libc/snprintf.py +36 -0
  1110. angr/procedures/libc/sprintf.py +25 -0
  1111. angr/procedures/libc/srand.py +7 -0
  1112. angr/procedures/libc/sscanf.py +13 -0
  1113. angr/procedures/libc/stpcpy.py +18 -0
  1114. angr/procedures/libc/strcat.py +14 -0
  1115. angr/procedures/libc/strchr.py +48 -0
  1116. angr/procedures/libc/strcmp.py +31 -0
  1117. angr/procedures/libc/strcpy.py +13 -0
  1118. angr/procedures/libc/strlen.py +114 -0
  1119. angr/procedures/libc/strncat.py +19 -0
  1120. angr/procedures/libc/strncmp.py +183 -0
  1121. angr/procedures/libc/strncpy.py +22 -0
  1122. angr/procedures/libc/strnlen.py +13 -0
  1123. angr/procedures/libc/strstr.py +101 -0
  1124. angr/procedures/libc/strtol.py +261 -0
  1125. angr/procedures/libc/strtoul.py +9 -0
  1126. angr/procedures/libc/system.py +13 -0
  1127. angr/procedures/libc/time.py +9 -0
  1128. angr/procedures/libc/tmpnam.py +20 -0
  1129. angr/procedures/libc/tolower.py +10 -0
  1130. angr/procedures/libc/toupper.py +10 -0
  1131. angr/procedures/libc/ungetc.py +20 -0
  1132. angr/procedures/libc/vsnprintf.py +17 -0
  1133. angr/procedures/libc/wchar.py +16 -0
  1134. angr/procedures/libstdcpp/__init__.py +0 -0
  1135. angr/procedures/libstdcpp/_unwind_resume.py +11 -0
  1136. angr/procedures/libstdcpp/std____throw_bad_alloc.py +13 -0
  1137. angr/procedures/libstdcpp/std____throw_bad_cast.py +13 -0
  1138. angr/procedures/libstdcpp/std____throw_length_error.py +13 -0
  1139. angr/procedures/libstdcpp/std____throw_logic_error.py +13 -0
  1140. angr/procedures/libstdcpp/std__terminate.py +13 -0
  1141. angr/procedures/linux_kernel/__init__.py +3 -0
  1142. angr/procedures/linux_kernel/access.py +18 -0
  1143. angr/procedures/linux_kernel/arch_prctl.py +34 -0
  1144. angr/procedures/linux_kernel/arm_user_helpers.py +59 -0
  1145. angr/procedures/linux_kernel/brk.py +18 -0
  1146. angr/procedures/linux_kernel/cwd.py +28 -0
  1147. angr/procedures/linux_kernel/fstat.py +138 -0
  1148. angr/procedures/linux_kernel/fstat64.py +170 -0
  1149. angr/procedures/linux_kernel/futex.py +17 -0
  1150. angr/procedures/linux_kernel/getegid.py +17 -0
  1151. angr/procedures/linux_kernel/geteuid.py +17 -0
  1152. angr/procedures/linux_kernel/getgid.py +17 -0
  1153. angr/procedures/linux_kernel/getpid.py +14 -0
  1154. angr/procedures/linux_kernel/getrlimit.py +24 -0
  1155. angr/procedures/linux_kernel/gettid.py +9 -0
  1156. angr/procedures/linux_kernel/getuid.py +17 -0
  1157. angr/procedures/linux_kernel/iovec.py +47 -0
  1158. angr/procedures/linux_kernel/lseek.py +42 -0
  1159. angr/procedures/linux_kernel/mmap.py +16 -0
  1160. angr/procedures/linux_kernel/mprotect.py +42 -0
  1161. angr/procedures/linux_kernel/munmap.py +8 -0
  1162. angr/procedures/linux_kernel/openat.py +26 -0
  1163. angr/procedures/linux_kernel/set_tid_address.py +8 -0
  1164. angr/procedures/linux_kernel/sigaction.py +19 -0
  1165. angr/procedures/linux_kernel/sigprocmask.py +23 -0
  1166. angr/procedures/linux_kernel/stat.py +23 -0
  1167. angr/procedures/linux_kernel/sysinfo.py +59 -0
  1168. angr/procedures/linux_kernel/tgkill.py +10 -0
  1169. angr/procedures/linux_kernel/time.py +34 -0
  1170. angr/procedures/linux_kernel/uid.py +30 -0
  1171. angr/procedures/linux_kernel/uname.py +29 -0
  1172. angr/procedures/linux_kernel/unlink.py +22 -0
  1173. angr/procedures/linux_kernel/vsyscall.py +16 -0
  1174. angr/procedures/linux_loader/__init__.py +3 -0
  1175. angr/procedures/linux_loader/_dl_initial_error_catch_tsd.py +7 -0
  1176. angr/procedures/linux_loader/_dl_rtld_lock.py +15 -0
  1177. angr/procedures/linux_loader/sim_loader.py +54 -0
  1178. angr/procedures/linux_loader/tls.py +40 -0
  1179. angr/procedures/msvcr/__getmainargs.py +16 -0
  1180. angr/procedures/msvcr/__init__.py +4 -0
  1181. angr/procedures/msvcr/_initterm.py +38 -0
  1182. angr/procedures/msvcr/fmode.py +31 -0
  1183. angr/procedures/ntdll/__init__.py +0 -0
  1184. angr/procedures/ntdll/exceptions.py +60 -0
  1185. angr/procedures/posix/__init__.py +3 -0
  1186. angr/procedures/posix/accept.py +29 -0
  1187. angr/procedures/posix/bind.py +13 -0
  1188. angr/procedures/posix/bzero.py +9 -0
  1189. angr/procedures/posix/chroot.py +27 -0
  1190. angr/procedures/posix/close.py +9 -0
  1191. angr/procedures/posix/closedir.py +7 -0
  1192. angr/procedures/posix/dup.py +56 -0
  1193. angr/procedures/posix/fcntl.py +10 -0
  1194. angr/procedures/posix/fdopen.py +76 -0
  1195. angr/procedures/posix/fileno.py +18 -0
  1196. angr/procedures/posix/fork.py +13 -0
  1197. angr/procedures/posix/getenv.py +35 -0
  1198. angr/procedures/posix/gethostbyname.py +43 -0
  1199. angr/procedures/posix/getpass.py +19 -0
  1200. angr/procedures/posix/getsockopt.py +11 -0
  1201. angr/procedures/posix/htonl.py +11 -0
  1202. angr/procedures/posix/htons.py +11 -0
  1203. angr/procedures/posix/inet_ntoa.py +59 -0
  1204. angr/procedures/posix/listen.py +13 -0
  1205. angr/procedures/posix/mmap.py +144 -0
  1206. angr/procedures/posix/open.py +18 -0
  1207. angr/procedures/posix/opendir.py +10 -0
  1208. angr/procedures/posix/poll.py +55 -0
  1209. angr/procedures/posix/pread64.py +46 -0
  1210. angr/procedures/posix/pthread.py +87 -0
  1211. angr/procedures/posix/pwrite64.py +46 -0
  1212. angr/procedures/posix/read.py +13 -0
  1213. angr/procedures/posix/readdir.py +62 -0
  1214. angr/procedures/posix/recv.py +13 -0
  1215. angr/procedures/posix/recvfrom.py +13 -0
  1216. angr/procedures/posix/select.py +48 -0
  1217. angr/procedures/posix/send.py +23 -0
  1218. angr/procedures/posix/setsockopt.py +9 -0
  1219. angr/procedures/posix/sigaction.py +23 -0
  1220. angr/procedures/posix/sim_time.py +48 -0
  1221. angr/procedures/posix/sleep.py +8 -0
  1222. angr/procedures/posix/socket.py +18 -0
  1223. angr/procedures/posix/strcasecmp.py +26 -0
  1224. angr/procedures/posix/strdup.py +18 -0
  1225. angr/procedures/posix/strtok_r.py +64 -0
  1226. angr/procedures/posix/syslog.py +15 -0
  1227. angr/procedures/posix/tz.py +9 -0
  1228. angr/procedures/posix/unlink.py +11 -0
  1229. angr/procedures/posix/usleep.py +8 -0
  1230. angr/procedures/posix/write.py +13 -0
  1231. angr/procedures/procedure_dict.py +50 -0
  1232. angr/procedures/stubs/CallReturn.py +13 -0
  1233. angr/procedures/stubs/NoReturnUnconstrained.py +13 -0
  1234. angr/procedures/stubs/Nop.py +7 -0
  1235. angr/procedures/stubs/PathTerminator.py +9 -0
  1236. angr/procedures/stubs/Redirect.py +18 -0
  1237. angr/procedures/stubs/ReturnChar.py +11 -0
  1238. angr/procedures/stubs/ReturnUnconstrained.py +24 -0
  1239. angr/procedures/stubs/UnresolvableCallTarget.py +9 -0
  1240. angr/procedures/stubs/UnresolvableJumpTarget.py +9 -0
  1241. angr/procedures/stubs/UserHook.py +18 -0
  1242. angr/procedures/stubs/__init__.py +3 -0
  1243. angr/procedures/stubs/b64_decode.py +15 -0
  1244. angr/procedures/stubs/caller.py +14 -0
  1245. angr/procedures/stubs/crazy_scanf.py +20 -0
  1246. angr/procedures/stubs/format_parser.py +669 -0
  1247. angr/procedures/stubs/syscall_stub.py +24 -0
  1248. angr/procedures/testing/__init__.py +3 -0
  1249. angr/procedures/testing/manyargs.py +9 -0
  1250. angr/procedures/testing/retreg.py +8 -0
  1251. angr/procedures/tracer/__init__.py +4 -0
  1252. angr/procedures/tracer/random.py +9 -0
  1253. angr/procedures/tracer/receive.py +23 -0
  1254. angr/procedures/tracer/transmit.py +26 -0
  1255. angr/procedures/uclibc/__init__.py +3 -0
  1256. angr/procedures/uclibc/__uClibc_main.py +10 -0
  1257. angr/procedures/win32/EncodePointer.py +7 -0
  1258. angr/procedures/win32/ExitProcess.py +9 -0
  1259. angr/procedures/win32/GetCommandLine.py +12 -0
  1260. angr/procedures/win32/GetCurrentProcessId.py +7 -0
  1261. angr/procedures/win32/GetCurrentThreadId.py +7 -0
  1262. angr/procedures/win32/GetLastInputInfo.py +40 -0
  1263. angr/procedures/win32/GetModuleHandle.py +29 -0
  1264. angr/procedures/win32/GetProcessAffinityMask.py +37 -0
  1265. angr/procedures/win32/InterlockedExchange.py +15 -0
  1266. angr/procedures/win32/IsProcessorFeaturePresent.py +7 -0
  1267. angr/procedures/win32/VirtualAlloc.py +114 -0
  1268. angr/procedures/win32/VirtualProtect.py +60 -0
  1269. angr/procedures/win32/__init__.py +3 -0
  1270. angr/procedures/win32/critical_section.py +12 -0
  1271. angr/procedures/win32/dynamic_loading.py +104 -0
  1272. angr/procedures/win32/file_handles.py +47 -0
  1273. angr/procedures/win32/gethostbyname.py +12 -0
  1274. angr/procedures/win32/heap.py +45 -0
  1275. angr/procedures/win32/is_bad_ptr.py +26 -0
  1276. angr/procedures/win32/local_storage.py +88 -0
  1277. angr/procedures/win32/mutex.py +11 -0
  1278. angr/procedures/win32/sim_time.py +135 -0
  1279. angr/procedures/win32/system_paths.py +35 -0
  1280. angr/procedures/win32_kernel/ExAllocatePool.py +13 -0
  1281. angr/procedures/win32_kernel/ExFreePoolWithTag.py +8 -0
  1282. angr/procedures/win32_kernel/__fastfail.py +15 -0
  1283. angr/procedures/win32_kernel/__init__.py +3 -0
  1284. angr/procedures/win_user32/__init__.py +0 -0
  1285. angr/procedures/win_user32/chars.py +15 -0
  1286. angr/procedures/win_user32/keyboard.py +14 -0
  1287. angr/procedures/win_user32/messagebox.py +49 -0
  1288. angr/project.py +860 -0
  1289. angr/protos/__init__.py +19 -0
  1290. angr/protos/cfg_pb2.py +42 -0
  1291. angr/protos/function_pb2.py +38 -0
  1292. angr/protos/primitives_pb2.py +59 -0
  1293. angr/protos/variables_pb2.py +55 -0
  1294. angr/protos/xrefs_pb2.py +36 -0
  1295. angr/py.typed +1 -0
  1296. angr/rustylib.cpython-311-darwin.so +0 -0
  1297. angr/serializable.py +66 -0
  1298. angr/sim_manager.py +971 -0
  1299. angr/sim_options.py +436 -0
  1300. angr/sim_procedure.py +626 -0
  1301. angr/sim_state.py +926 -0
  1302. angr/sim_state_options.py +403 -0
  1303. angr/sim_type.py +4026 -0
  1304. angr/sim_variable.py +470 -0
  1305. angr/simos/__init__.py +47 -0
  1306. angr/simos/cgc.py +153 -0
  1307. angr/simos/javavm.py +458 -0
  1308. angr/simos/linux.py +509 -0
  1309. angr/simos/simos.py +444 -0
  1310. angr/simos/snimmuc_nxp.py +149 -0
  1311. angr/simos/userland.py +163 -0
  1312. angr/simos/windows.py +615 -0
  1313. angr/simos/xbox.py +32 -0
  1314. angr/slicer.py +352 -0
  1315. angr/state_hierarchy.py +262 -0
  1316. angr/state_plugins/__init__.py +84 -0
  1317. angr/state_plugins/callstack.py +478 -0
  1318. angr/state_plugins/cgc.py +155 -0
  1319. angr/state_plugins/debug_variables.py +192 -0
  1320. angr/state_plugins/filesystem.py +463 -0
  1321. angr/state_plugins/gdb.py +148 -0
  1322. angr/state_plugins/globals.py +65 -0
  1323. angr/state_plugins/heap/__init__.py +15 -0
  1324. angr/state_plugins/heap/heap_base.py +128 -0
  1325. angr/state_plugins/heap/heap_brk.py +136 -0
  1326. angr/state_plugins/heap/heap_freelist.py +213 -0
  1327. angr/state_plugins/heap/heap_libc.py +46 -0
  1328. angr/state_plugins/heap/heap_ptmalloc.py +620 -0
  1329. angr/state_plugins/heap/utils.py +22 -0
  1330. angr/state_plugins/history.py +564 -0
  1331. angr/state_plugins/inspect.py +375 -0
  1332. angr/state_plugins/javavm_classloader.py +134 -0
  1333. angr/state_plugins/jni_references.py +95 -0
  1334. angr/state_plugins/libc.py +1263 -0
  1335. angr/state_plugins/light_registers.py +168 -0
  1336. angr/state_plugins/log.py +84 -0
  1337. angr/state_plugins/loop_data.py +92 -0
  1338. angr/state_plugins/plugin.py +176 -0
  1339. angr/state_plugins/posix.py +703 -0
  1340. angr/state_plugins/preconstrainer.py +196 -0
  1341. angr/state_plugins/scratch.py +173 -0
  1342. angr/state_plugins/sim_action.py +326 -0
  1343. angr/state_plugins/sim_action_object.py +271 -0
  1344. angr/state_plugins/sim_event.py +59 -0
  1345. angr/state_plugins/solver.py +1128 -0
  1346. angr/state_plugins/symbolizer.py +291 -0
  1347. angr/state_plugins/trace_additions.py +738 -0
  1348. angr/state_plugins/uc_manager.py +94 -0
  1349. angr/state_plugins/unicorn_engine.py +1920 -0
  1350. angr/state_plugins/view.py +340 -0
  1351. angr/storage/__init__.py +15 -0
  1352. angr/storage/file.py +1210 -0
  1353. angr/storage/memory_mixins/__init__.py +317 -0
  1354. angr/storage/memory_mixins/actions_mixin.py +72 -0
  1355. angr/storage/memory_mixins/address_concretization_mixin.py +384 -0
  1356. angr/storage/memory_mixins/bvv_conversion_mixin.py +73 -0
  1357. angr/storage/memory_mixins/clouseau_mixin.py +137 -0
  1358. angr/storage/memory_mixins/conditional_store_mixin.py +25 -0
  1359. angr/storage/memory_mixins/convenient_mappings_mixin.py +256 -0
  1360. angr/storage/memory_mixins/default_filler_mixin.py +144 -0
  1361. angr/storage/memory_mixins/dirty_addrs_mixin.py +11 -0
  1362. angr/storage/memory_mixins/hex_dumper_mixin.py +82 -0
  1363. angr/storage/memory_mixins/javavm_memory_mixin.py +392 -0
  1364. angr/storage/memory_mixins/keyvalue_memory_mixin.py +43 -0
  1365. angr/storage/memory_mixins/label_merger_mixin.py +31 -0
  1366. angr/storage/memory_mixins/memory_mixin.py +175 -0
  1367. angr/storage/memory_mixins/multi_value_merger_mixin.py +79 -0
  1368. angr/storage/memory_mixins/name_resolution_mixin.py +67 -0
  1369. angr/storage/memory_mixins/paged_memory/__init__.py +0 -0
  1370. angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +266 -0
  1371. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +743 -0
  1372. angr/storage/memory_mixins/paged_memory/paged_memory_multivalue_mixin.py +65 -0
  1373. angr/storage/memory_mixins/paged_memory/pages/__init__.py +26 -0
  1374. angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
  1375. angr/storage/memory_mixins/paged_memory/pages/cooperation.py +341 -0
  1376. angr/storage/memory_mixins/paged_memory/pages/history_tracking_mixin.py +92 -0
  1377. angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +55 -0
  1378. angr/storage/memory_mixins/paged_memory/pages/list_page.py +338 -0
  1379. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +324 -0
  1380. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +419 -0
  1381. angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +36 -0
  1382. angr/storage/memory_mixins/paged_memory/pages/refcount_mixin.py +52 -0
  1383. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +529 -0
  1384. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +36 -0
  1385. angr/storage/memory_mixins/paged_memory/stack_allocation_mixin.py +74 -0
  1386. angr/storage/memory_mixins/regioned_memory/__init__.py +17 -0
  1387. angr/storage/memory_mixins/regioned_memory/abstract_address_descriptor.py +36 -0
  1388. angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +31 -0
  1389. angr/storage/memory_mixins/regioned_memory/region_category_mixin.py +9 -0
  1390. angr/storage/memory_mixins/regioned_memory/region_data.py +246 -0
  1391. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +241 -0
  1392. angr/storage/memory_mixins/regioned_memory/regioned_address_concretization_mixin.py +119 -0
  1393. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +442 -0
  1394. angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +69 -0
  1395. angr/storage/memory_mixins/simple_interface_mixin.py +71 -0
  1396. angr/storage/memory_mixins/simplification_mixin.py +15 -0
  1397. angr/storage/memory_mixins/size_resolution_mixin.py +143 -0
  1398. angr/storage/memory_mixins/slotted_memory.py +140 -0
  1399. angr/storage/memory_mixins/smart_find_mixin.py +161 -0
  1400. angr/storage/memory_mixins/symbolic_merger_mixin.py +16 -0
  1401. angr/storage/memory_mixins/top_merger_mixin.py +25 -0
  1402. angr/storage/memory_mixins/underconstrained_mixin.py +67 -0
  1403. angr/storage/memory_mixins/unwrapper_mixin.py +26 -0
  1404. angr/storage/memory_object.py +195 -0
  1405. angr/tablespecs.py +91 -0
  1406. angr/unicornlib.dylib +0 -0
  1407. angr/utils/__init__.py +46 -0
  1408. angr/utils/ail.py +176 -0
  1409. angr/utils/algo.py +34 -0
  1410. angr/utils/balancer.py +776 -0
  1411. angr/utils/bits.py +46 -0
  1412. angr/utils/constants.py +9 -0
  1413. angr/utils/cowdict.py +63 -0
  1414. angr/utils/cpp.py +17 -0
  1415. angr/utils/doms.py +150 -0
  1416. angr/utils/dynamic_dictlist.py +89 -0
  1417. angr/utils/endness.py +18 -0
  1418. angr/utils/enums_conv.py +97 -0
  1419. angr/utils/env.py +12 -0
  1420. angr/utils/formatting.py +128 -0
  1421. angr/utils/funcid.py +244 -0
  1422. angr/utils/graph.py +981 -0
  1423. angr/utils/lazy_import.py +13 -0
  1424. angr/utils/library.py +236 -0
  1425. angr/utils/loader.py +55 -0
  1426. angr/utils/mp.py +66 -0
  1427. angr/utils/orderedset.py +74 -0
  1428. angr/utils/ssa/__init__.py +455 -0
  1429. angr/utils/ssa/tmp_uses_collector.py +23 -0
  1430. angr/utils/ssa/vvar_uses_collector.py +36 -0
  1431. angr/utils/strings.py +20 -0
  1432. angr/utils/tagged_interval_map.py +112 -0
  1433. angr/utils/timing.py +74 -0
  1434. angr/utils/types.py +193 -0
  1435. angr/utils/vex.py +11 -0
  1436. angr/vaults.py +367 -0
  1437. angr-9.2.192.dist-info/METADATA +112 -0
  1438. angr-9.2.192.dist-info/RECORD +1442 -0
  1439. angr-9.2.192.dist-info/WHEEL +6 -0
  1440. angr-9.2.192.dist-info/entry_points.txt +2 -0
  1441. angr-9.2.192.dist-info/licenses/LICENSE +27 -0
  1442. angr-9.2.192.dist-info/top_level.txt +1 -0
@@ -0,0 +1,3662 @@
1
+ # pylint:disable=too-many-boolean-expressions
2
+ from __future__ import annotations
3
+ from typing import Any, NamedTuple, TYPE_CHECKING
4
+ import copy
5
+ import logging
6
+ import enum
7
+ from collections import defaultdict, namedtuple
8
+ from collections.abc import Iterable
9
+ from dataclasses import dataclass
10
+
11
+ import networkx
12
+ import capstone
13
+
14
+ from angr import ailment
15
+ from angr.ailment.block_walker import AILBlockViewer
16
+ from angr.ailment.expression import VirtualVariable
17
+ from angr.errors import AngrDecompilationError
18
+ from angr.knowledge_base import KnowledgeBase
19
+ from angr.knowledge_plugins.functions import Function
20
+ from angr.knowledge_plugins.cfg.memory_data import MemoryDataSort
21
+ from angr.knowledge_plugins.key_definitions import atoms
22
+ from angr.codenode import BlockNode
23
+ from angr.utils import timethis
24
+ from angr.utils.ssa import is_phi_assignment
25
+ from angr.utils.graph import GraphUtils
26
+ from angr.utils.types import dereference_simtype_by_lib
27
+ from angr.calling_conventions import SimRegArg, SimStackArg, SimFunctionArgument, SimCCUsercall
28
+ from angr.sim_type import (
29
+ SimType,
30
+ SimTypeChar,
31
+ SimTypeInt,
32
+ SimTypeLongLong,
33
+ SimTypeShort,
34
+ SimTypeFunction,
35
+ SimTypeBottom,
36
+ SimTypeFloat,
37
+ SimTypePointer,
38
+ SimStruct,
39
+ SimTypeArray,
40
+ SimCppClass,
41
+ )
42
+ from angr.analyses.stack_pointer_tracker import Register, OffsetVal
43
+ from angr.sim_variable import SimVariable, SimStackVariable, SimRegisterVariable, SimMemoryVariable
44
+ from angr.procedures.stubs.UnresolvableCallTarget import UnresolvableCallTarget
45
+ from angr.procedures.stubs.UnresolvableJumpTarget import UnresolvableJumpTarget
46
+ from angr.analyses import Analysis, register_analysis
47
+ from angr.analyses.cfg.cfg_base import CFGBase
48
+ from angr.analyses.reaching_definitions import ReachingDefinitionsAnalysis
49
+ from angr.analyses.typehoon import Typehoon
50
+ from .ail_simplifier import AILSimplifier
51
+ from .ssailification.ssailification import Ssailification
52
+ from .stack_item import StackItem, StackItemType
53
+ from .return_maker import ReturnMaker
54
+ from .ailgraph_walker import AILGraphWalker, RemoveNodeNotice
55
+ from .optimization_passes import (
56
+ OptimizationPassStage,
57
+ StackCanarySimplifier,
58
+ TagSlicer,
59
+ DUPLICATING_OPTS,
60
+ CONDENSING_OPTS,
61
+ )
62
+ from .semantic_naming import SemanticNamingOrchestrator
63
+
64
+ if TYPE_CHECKING:
65
+ from angr.knowledge_plugins.cfg import CFGModel
66
+ from .notes import DecompilationNote
67
+ from .decompilation_cache import DecompilationCache
68
+ from .peephole_optimizations import PeepholeOptimizationStmtBase, PeepholeOptimizationExprBase
69
+
70
+ l = logging.getLogger(name=__name__)
71
+
72
+
73
+ BlockCache = namedtuple("BlockCache", ("rd", "prop"))
74
+
75
+
76
+ class ClinicMode(enum.Enum):
77
+ """
78
+ Analysis mode for Clinic.
79
+ """
80
+
81
+ DECOMPILE = 1
82
+ COLLECT_DATA_REFS = 2
83
+
84
+
85
+ @dataclass
86
+ class DataRefDesc:
87
+ """
88
+ The fields of this class is compatible with items inside IRSB.data_refs.
89
+ """
90
+
91
+ data_addr: int
92
+ data_size: int
93
+ block_addr: int
94
+ stmt_idx: int
95
+ ins_addr: int
96
+ data_type_str: str
97
+
98
+
99
+ class ClinicStage(enum.IntEnum):
100
+ """
101
+ Different stages of treating an ailment.
102
+ """
103
+
104
+ INITIALIZATION = 0
105
+ AIL_GRAPH_CONVERSION = 1
106
+ MAKE_RETURN_SITES = 2
107
+ MAKE_ARGUMENT_LIST = 3
108
+ PRE_SSA_LEVEL0_FIXUPS = 4
109
+ SSA_LEVEL0_TRANSFORMATION = 5
110
+ CONSTANT_PROPAGATION = 6
111
+ TRACK_STACK_POINTERS = 7
112
+ PRE_SSA_LEVEL1_SIMPLIFICATIONS = 8
113
+ SSA_LEVEL1_TRANSFORMATION = 9
114
+ POST_SSA_LEVEL1_SIMPLIFICATIONS = 10
115
+ MAKE_CALLSITES = 11
116
+ POST_CALLSITES = 12
117
+ RECOVER_VARIABLES = 13
118
+ SEMANTIC_VARIABLE_NAMING = 14
119
+ COLLECT_EXTERNS = 15
120
+
121
+
122
+ class Clinic(Analysis):
123
+ """
124
+ A Clinic deals with AILments.
125
+ """
126
+
127
+ _ail_manager: ailment.Manager
128
+
129
+ def __init__(
130
+ self,
131
+ func: Function,
132
+ remove_dead_memdefs=False,
133
+ exception_edges=False,
134
+ sp_tracker_track_memory=True,
135
+ fold_callexprs_into_conditions=False,
136
+ insert_labels=True,
137
+ optimization_passes=None,
138
+ cfg=None,
139
+ peephole_optimizations: None | (
140
+ Iterable[type[PeepholeOptimizationStmtBase] | type[PeepholeOptimizationExprBase]]
141
+ ) = None, # pylint:disable=line-too-long
142
+ must_struct: set[str] | None = None,
143
+ variable_kb: KnowledgeBase | None = None,
144
+ reset_variable_names=False,
145
+ rewrite_ites_to_diamonds=True,
146
+ cache: DecompilationCache | None = None,
147
+ mode: ClinicMode = ClinicMode.DECOMPILE,
148
+ sp_shift: int = 0,
149
+ inline_functions: set[Function] | None = None,
150
+ inlined_counts: dict[int, int] | None = None,
151
+ inlining_parents: set[int] | None = None,
152
+ vvar_id_start: int = 0,
153
+ optimization_scratch: dict[str, Any] | None = None,
154
+ desired_variables: set[str] | None = None,
155
+ force_loop_single_exit: bool = True,
156
+ refine_loops_with_single_successor: bool = False,
157
+ complete_successors: bool = False,
158
+ max_type_constraints: int = 100_000,
159
+ type_constraint_set_degradation_threshold: int = 150,
160
+ ail_graph: networkx.DiGraph | None = None,
161
+ arg_vvars: dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]] | None = None,
162
+ start_stage: ClinicStage | None = ClinicStage.INITIALIZATION,
163
+ end_stage: ClinicStage | None = None,
164
+ skip_stages: tuple[ClinicStage, ...] = (),
165
+ notes: dict[str, DecompilationNote] | None = None,
166
+ static_vvars: dict | None = None,
167
+ static_buffers: dict | None = None,
168
+ semvar_naming: bool = True,
169
+ ):
170
+ if not func.normalized and mode == ClinicMode.DECOMPILE:
171
+ raise ValueError("Decompilation must work on normalized function graphs.")
172
+
173
+ self.function = func
174
+
175
+ self.graph = None
176
+ self.cc_graph: networkx.DiGraph | None = None
177
+ self.unoptimized_graph: networkx.DiGraph | None = None
178
+ self.arg_list = None
179
+ self.arg_vvars: dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]] | None = None
180
+ self.func_args = None
181
+ self.func_ret_var = SimVariable(0, "__retvar", "__retvar")
182
+ self.variable_kb = variable_kb
183
+ self.externs: set[SimMemoryVariable] = set()
184
+ self.data_refs: dict[int, list[DataRefDesc]] = {} # data address to data reference description
185
+ self.optimization_scratch = optimization_scratch if optimization_scratch is not None else {}
186
+
187
+ self._func_graph: networkx.DiGraph | None = None
188
+ self._init_ail_graph = ail_graph
189
+ self._init_arg_vvars = arg_vvars
190
+ self._start_stage = start_stage if start_stage is not None else ClinicStage.INITIALIZATION
191
+ self._end_stage = end_stage if end_stage is not None else max(ClinicStage.__members__.values())
192
+ self._skip_stages = skip_stages
193
+
194
+ self._blocks_by_addr_and_size = {}
195
+ self.entry_node_addr: tuple[int, int | None] = self.function.addr, None
196
+
197
+ self._fold_callexprs_into_conditions = fold_callexprs_into_conditions
198
+ self._insert_labels = insert_labels
199
+ self._remove_dead_memdefs = remove_dead_memdefs
200
+ self._exception_edges = exception_edges
201
+ self._sp_tracker_track_memory = sp_tracker_track_memory
202
+ self._cfg: CFGModel | None = cfg
203
+ self.peephole_optimizations = peephole_optimizations
204
+ self._must_struct = must_struct
205
+ self._reset_variable_names = reset_variable_names
206
+ self._rewrite_ites_to_diamonds = rewrite_ites_to_diamonds
207
+ self.reaching_definitions: ReachingDefinitionsAnalysis | None = None
208
+ self._cache = cache
209
+ self._mode = mode
210
+ self._max_type_constraints = max_type_constraints
211
+ self._type_constraint_set_degradation_threshold = type_constraint_set_degradation_threshold
212
+ self.vvar_id_start = vvar_id_start
213
+ self.vvar_to_vvar: dict[int, int] | None = None
214
+ # during SSA conversion, we create secondary stack variables because they overlap and are larger than the
215
+ # actual stack variables. these secondary stack variables can be safely eliminated if not used by anything.
216
+ self.secondary_stackvars: set[int] = set()
217
+
218
+ self.notes = notes if notes is not None else {}
219
+ self.static_vvars = static_vvars if static_vvars is not None else {}
220
+ self.static_buffers = static_buffers if static_buffers is not None else {}
221
+ self._semvar_naming = semvar_naming
222
+
223
+ if not semvar_naming and ClinicStage.SEMANTIC_VARIABLE_NAMING not in self._skip_stages:
224
+ self._skip_stages += (ClinicStage.SEMANTIC_VARIABLE_NAMING,)
225
+
226
+ #
227
+ # intermediate variables used during decompilation
228
+ #
229
+
230
+ self._ail_graph: networkx.DiGraph = None # type:ignore
231
+ self._spt = None
232
+ # cached block-level reaching definition analysis results and propagator results
233
+ self._block_simplification_cache: dict[ailment.Block, NamedTuple] | None = {}
234
+ self._preserve_vvar_ids: set[int] = set()
235
+ self._type_hints: list[tuple[atoms.VirtualVariable | atoms.MemoryLocation, str]] = []
236
+
237
+ # inlining help
238
+ self._sp_shift = sp_shift
239
+ self._max_stack_depth = 0
240
+ self._inline_functions = inline_functions if inline_functions else set()
241
+ self._inlined_counts = {} if inlined_counts is None else inlined_counts
242
+ self._inlining_parents = inlining_parents or ()
243
+ self._desired_variables = desired_variables
244
+ self._force_loop_single_exit = force_loop_single_exit
245
+ self._refine_loops_with_single_successor = refine_loops_with_single_successor
246
+ self._complete_successors = complete_successors
247
+
248
+ self._register_save_areas_removed: bool = False
249
+ self.edges_to_remove: list[tuple[tuple[int, int | None], tuple[int, int | None]]] = []
250
+ self.copied_var_ids: set[int] = set()
251
+
252
+ self._new_block_addrs: set[int] = set()
253
+
254
+ # a reference to the Typehoon type inference engine; useful for debugging and loading stats post decompilation
255
+ self.typehoon: Typehoon | None = None
256
+
257
+ # sanity checks
258
+ if not self.kb.functions:
259
+ l.warning("No function is available in kb.functions. It will lead to a suboptimal conversion result.")
260
+
261
+ if optimization_passes is not None:
262
+ self._optimization_passes = optimization_passes
263
+ else:
264
+ self._optimization_passes = []
265
+
266
+ self.stack_items: dict[int, StackItem] = {}
267
+ if self.project.arch.call_pushes_ret:
268
+ self.stack_items[0] = StackItem(0, self.project.arch.bytes, "ret_addr", StackItemType.RET_ADDR)
269
+
270
+ # Set up the function graph according to configurations
271
+ self._set_function_graph()
272
+
273
+ if self._mode == ClinicMode.DECOMPILE:
274
+ self._analyze_for_decompiling()
275
+ if self._end_stage >= ClinicStage.MAKE_CALLSITES:
276
+ self._constrain_callee_prototypes()
277
+ elif self._mode == ClinicMode.COLLECT_DATA_REFS:
278
+ self._analyze_for_data_refs()
279
+ else:
280
+ raise TypeError(f"Unsupported analysis mode {self._mode}")
281
+
282
+ #
283
+ # Public methods
284
+ #
285
+
286
+ def block(self, addr, size):
287
+ """
288
+ Get the converted block at the given specific address with the given size.
289
+
290
+ :param int addr:
291
+ :param int size:
292
+ :return:
293
+ """
294
+
295
+ try:
296
+ return self._blocks_by_addr_and_size[(addr, size)] if self._blocks_by_addr_and_size is not None else None
297
+ except KeyError:
298
+ return None
299
+
300
+ def dbg_repr(self):
301
+ """
302
+
303
+ :return:
304
+ """
305
+ assert self.graph is not None
306
+
307
+ s = ""
308
+
309
+ for block in sorted(self.graph.nodes(), key=lambda x: x.addr):
310
+ s += str(block) + "\n\n"
311
+
312
+ return s
313
+
314
+ #
315
+ # Private methods
316
+ #
317
+
318
+ def _analyze_for_decompiling(self):
319
+ # initialize the AIL conversion manager
320
+ self._ail_manager = ailment.Manager(arch=self.project.arch)
321
+
322
+ ail_graph = self._init_ail_graph if self._init_ail_graph is not None else self._decompilation_graph_recovery()
323
+ if not ail_graph:
324
+ return
325
+ if self._start_stage <= ClinicStage.INITIALIZATION:
326
+ ail_graph = self._decompilation_fixups(ail_graph)
327
+
328
+ if self._inline_functions:
329
+ self._max_stack_depth += self.calculate_stack_depth()
330
+ ail_graph = self._inline_child_functions(ail_graph)
331
+
332
+ ail_graph = self._decompilation_simplifications(ail_graph)
333
+
334
+ if self._desired_variables:
335
+ ail_graph = self._slice_variables(ail_graph)
336
+ self.graph = ail_graph
337
+
338
+ def _decompilation_graph_recovery(self):
339
+ is_pcode_arch = ":" in self.project.arch.name
340
+
341
+ # Remove alignment blocks
342
+ self._update_progress(5.0, text="Removing alignment blocks")
343
+ self._remove_alignment_blocks()
344
+
345
+ # if the graph is empty, don't continue
346
+ if not self._func_graph:
347
+ return None
348
+
349
+ # Make sure calling conventions of all functions that the current function calls have been recovered
350
+ if not is_pcode_arch:
351
+ self._update_progress(10.0, text="Recovering calling conventions")
352
+ self._recover_calling_conventions()
353
+
354
+ # Convert VEX blocks to AIL blocks and then simplify them
355
+
356
+ self._update_progress(20.0, text="Converting VEX to AIL")
357
+ self._convert_all()
358
+
359
+ return self._make_ailgraph()
360
+
361
+ def _decompilation_fixups(self, ail_graph):
362
+ is_pcode_arch = ":" in self.project.arch.name
363
+
364
+ self._remove_redundant_jump_blocks(ail_graph)
365
+ # _fix_abnormal_switch_case_heads may re-lift from VEX blocks, so it should be placed as high up as possible
366
+ self._fix_abnormal_switch_case_heads(ail_graph)
367
+ if self._rewrite_ites_to_diamonds:
368
+ self._rewrite_ite_expressions(ail_graph)
369
+ self._remove_redundant_jump_blocks(ail_graph)
370
+ if self._insert_labels:
371
+ self._insert_block_labels(ail_graph)
372
+
373
+ # Run simplification passes
374
+ self._update_progress(22.0, text="Optimizing fresh ailment graph")
375
+ ail_graph = self._run_simplification_passes(ail_graph, OptimizationPassStage.AFTER_AIL_GRAPH_CREATION)
376
+
377
+ # Fix "fake" indirect jumps and calls
378
+ self._update_progress(25.0, text="Analyzing simple indirect jumps")
379
+ ail_graph = self._replace_single_target_indirect_transitions(ail_graph)
380
+
381
+ # Fix tail calls
382
+ self._update_progress(26.0, text="Analyzing tail calls")
383
+ ail_graph = self._replace_tail_jumps_with_calls(ail_graph)
384
+
385
+ # Fix special calls
386
+ self._update_progress(28.0, text="Analyzing special calls")
387
+ ail_graph = self._fix_special_call_calling_conventions(ail_graph)
388
+
389
+ if is_pcode_arch:
390
+ self._update_progress(29.0, text="Recovering calling conventions (AIL mode)")
391
+ self._recover_calling_conventions(func_graph=ail_graph)
392
+
393
+ return self._apply_callsite_prototype_and_calling_convention(ail_graph)
394
+
395
+ def _slice_variables(self, ail_graph: networkx.DiGraph[ailment.Block]) -> networkx.DiGraph[ailment.Block]:
396
+ assert self.variable_kb is not None and self._desired_variables is not None
397
+
398
+ nodes_index = {(n.addr, n.idx): n for n in ail_graph.nodes()}
399
+
400
+ vfm = self.variable_kb.variables.function_managers[self.function.addr]
401
+ for v_name in self._desired_variables:
402
+ v = next(iter(vv for vv in vfm._unified_variables if vv.name == v_name))
403
+ for va in vfm.get_variable_accesses(v):
404
+ assert va.location.block_addr is not None
405
+ assert va.location.stmt_idx is not None
406
+ nodes_index[(va.location.block_addr, va.location.block_idx)].statements[va.location.stmt_idx].tags[
407
+ "keep_in_slice"
408
+ ] = True
409
+
410
+ a = TagSlicer(
411
+ self.function,
412
+ graph=ail_graph,
413
+ variable_kb=self.variable_kb,
414
+ )
415
+ if a.out_graph:
416
+ # use the new graph
417
+ ail_graph = a.out_graph
418
+ return ail_graph
419
+
420
+ def _inline_child_functions(self, ail_graph):
421
+ for blk in ail_graph.nodes():
422
+ for idx, stmt in enumerate(blk.statements):
423
+ if isinstance(stmt, ailment.Stmt.Call) and isinstance(stmt.target, ailment.Expr.Const):
424
+ assert self.function._function_manager is not None
425
+ callee = self.function._function_manager.function(stmt.target.value)
426
+ if (
427
+ callee is None
428
+ or callee.addr == self.function.addr
429
+ or callee.addr in self._inlining_parents
430
+ or callee not in self._inline_functions
431
+ or callee.is_plt
432
+ or callee.is_simprocedure
433
+ ):
434
+ continue
435
+
436
+ ail_graph = self._inline_call(ail_graph, blk, idx, callee)
437
+ return ail_graph
438
+
439
+ @staticmethod
440
+ def _inline_fix_block_phi_stmts(block: ailment.Block, new_block_idx: int) -> None:
441
+ # update the source block ID of all phi variables
442
+ for idx, stmt in enumerate(block.statements):
443
+ if is_phi_assignment(stmt):
444
+ new_src_and_vvars: list[tuple[tuple[int, int | None], VirtualVariable | None]] = [
445
+ ((src_block_addr, new_block_idx), vvar) for (src_block_addr, _), vvar in stmt.src.src_and_vvars
446
+ ]
447
+ new_src = ailment.Expr.Phi(stmt.src.idx, stmt.src.bits, new_src_and_vvars, **stmt.src.tags)
448
+ new_stmt = ailment.Stmt.Assignment(stmt.idx, stmt.dst, new_src, **stmt.tags)
449
+ block.statements[idx] = new_stmt
450
+
451
+ def _inline_call(self, ail_graph: networkx.DiGraph, caller_block: ailment.Block, call_idx: int, callee: Function):
452
+ callee_clinic = self.project.analyses.Clinic(
453
+ callee,
454
+ mode=ClinicMode.DECOMPILE,
455
+ inline_functions=self._inline_functions,
456
+ inlining_parents=(*self._inlining_parents, self.function.addr),
457
+ inlined_counts=self._inlined_counts,
458
+ optimization_passes=[StackCanarySimplifier],
459
+ sp_shift=self._max_stack_depth,
460
+ vvar_id_start=self.vvar_id_start,
461
+ fail_fast=self._fail_fast, # type: ignore
462
+ )
463
+ self.vvar_id_start = callee_clinic.vvar_id_start + 1
464
+ self._max_stack_depth = callee_clinic._max_stack_depth
465
+ callee_graph = callee_clinic.copy_graph()
466
+
467
+ # uniquely mark all the blocks in case of duplicates (e.g., foo(); foo();)
468
+ self._inlined_counts.setdefault(callee.addr, 0)
469
+ block_idx = self._inlined_counts[callee.addr]
470
+ for blk in callee_graph.nodes():
471
+ blk.idx = block_idx
472
+ self._inline_fix_block_phi_stmts(blk, block_idx)
473
+ self._inlined_counts[callee.addr] += 1
474
+
475
+ # figure out where the callee should start at and return to
476
+ callee_start = next(n for n in callee_graph if n.addr == callee.addr)
477
+ caller_successors = list(ail_graph.out_edges(caller_block, data=True))
478
+ assert len(caller_successors) == 1
479
+ caller_successor = caller_successors[0][1]
480
+ ail_graph.remove_edge(caller_block, caller_successor)
481
+
482
+ # update all callee return nodes with caller successor
483
+ ail_graph = networkx.union(ail_graph, callee_graph)
484
+ for blk in callee_graph.nodes():
485
+ for idx, stmt in enumerate(list(blk.statements)):
486
+ if isinstance(stmt, ailment.Stmt.Return):
487
+ # replace the return statement with an assignment to the return register
488
+ blk.statements.pop(idx)
489
+
490
+ if stmt.ret_exprs and self.project.arch.ret_offset is not None:
491
+ assign_to_retreg = ailment.Stmt.Assignment(
492
+ self._ail_manager.next_atom(),
493
+ ailment.Expr.Register(
494
+ self._ail_manager.next_atom(),
495
+ None,
496
+ self.project.arch.ret_offset,
497
+ self.project.arch.bits,
498
+ ),
499
+ stmt.ret_exprs[0],
500
+ **stmt.tags,
501
+ )
502
+ blk.statements.insert(idx, assign_to_retreg)
503
+ idx += 1
504
+ ail_graph.add_edge(blk, caller_successor)
505
+ break
506
+
507
+ # update the call edge
508
+ # first, remove the call statement. this is a type error but will be resolved later
509
+ caller_block.statements[call_idx] = None # type: ignore
510
+ if (
511
+ isinstance(caller_block.statements[call_idx - 2], ailment.Stmt.Store)
512
+ and caller_block.statements[call_idx - 2].data.value == caller_successor.addr
513
+ ):
514
+ # don't push the return address
515
+ caller_block.statements.pop(call_idx - 5) # t6 = rsp<8>
516
+ caller_block.statements.pop(call_idx - 5) # t5 = (t6 - 0x8<64>)
517
+ caller_block.statements.pop(call_idx - 5) # rsp<8> = t5
518
+ caller_block.statements.pop(
519
+ call_idx - 5
520
+ ) # STORE(addr=t5, data=0x40121b<64>, size=8, endness=Iend_LE, guard=None)
521
+ caller_block.statements.pop(call_idx - 5) # t7 = (t5 - 0x80<64>) <- wtf is this??
522
+ elif (
523
+ isinstance(caller_block.statements[call_idx - 1], ailment.Stmt.Store)
524
+ and caller_block.statements[call_idx - 1].addr.base == "stack_base"
525
+ and caller_block.statements[call_idx - 1].data.value == caller_successor.addr
526
+ ):
527
+ caller_block.statements.pop(call_idx - 1) # s_10 =L 0x401225<64><8>
528
+
529
+ # update caller_block to setup parameters
530
+ if callee_clinic.arg_vvars:
531
+ for arg_idx in sorted(callee_clinic.arg_vvars.keys()):
532
+ param_vvar, reg_arg = callee_clinic.arg_vvars[arg_idx]
533
+ if isinstance(reg_arg, SimRegisterVariable):
534
+ reg_offset = reg_arg.reg
535
+ stmt = ailment.Stmt.Assignment(
536
+ self._ail_manager.next_atom(),
537
+ param_vvar,
538
+ ailment.Expr.Register(
539
+ self._ail_manager.next_atom(),
540
+ None,
541
+ reg_offset,
542
+ reg_arg.bits,
543
+ ins_addr=caller_block.addr + caller_block.original_size,
544
+ ),
545
+ ins_addr=caller_block.addr + caller_block.original_size,
546
+ )
547
+ caller_block.statements.append(stmt)
548
+ else:
549
+ raise NotImplementedError("Unsupported parameter type")
550
+
551
+ caller_block.statements = [s for s in caller_block.statements if s is not None]
552
+
553
+ ail_graph.add_edge(caller_block, callee_start)
554
+
555
+ return ail_graph
556
+
557
+ def calculate_stack_depth(self):
558
+ # we need to reserve space for our own stack
559
+ spt = self._track_stack_pointers()
560
+ stack_offsets = spt.offsets_for(self.project.arch.sp_offset)
561
+ if max(stack_offsets) > 2 ** (self.project.arch.bits - 1):
562
+ # why is this unsigned...
563
+ depth = min(s for s in stack_offsets if s > 2 ** (self.project.arch.bits - 1)) - 2**self.project.arch.bits
564
+ else:
565
+ depth = min(stack_offsets)
566
+
567
+ if spt.inconsistent_for(self.project.arch.sp_offset):
568
+ l.warning("Inconsistency found during stack pointer tracking. Stack depth may be incorrect.")
569
+ depth -= 0x1000
570
+
571
+ return depth
572
+
573
+ def _decompilation_simplifications(self, ail_graph):
574
+ self.arg_vvars = self._init_arg_vvars if self._init_arg_vvars is not None else {}
575
+ self.func_args = {arg_vvar for arg_vvar, _ in self.arg_vvars.values()}
576
+ self._ail_graph = ail_graph
577
+
578
+ stages = {
579
+ ClinicStage.MAKE_RETURN_SITES: self._stage_make_return_sites,
580
+ ClinicStage.MAKE_ARGUMENT_LIST: self._stage_make_function_argument_list,
581
+ ClinicStage.PRE_SSA_LEVEL0_FIXUPS: self._stage_pre_ssa_level0_fixups,
582
+ ClinicStage.SSA_LEVEL0_TRANSFORMATION: self._stage_transform_to_ssa_level0,
583
+ ClinicStage.CONSTANT_PROPAGATION: self._stage_constant_propagation,
584
+ ClinicStage.TRACK_STACK_POINTERS: self._stage_track_stack_pointers,
585
+ ClinicStage.PRE_SSA_LEVEL1_SIMPLIFICATIONS: self._stage_pre_ssa_level1_simplifications,
586
+ ClinicStage.SSA_LEVEL1_TRANSFORMATION: self._stage_transform_to_ssa_level1,
587
+ ClinicStage.POST_SSA_LEVEL1_SIMPLIFICATIONS: self._stage_post_ssa_level1_simplifications,
588
+ ClinicStage.MAKE_CALLSITES: self._stage_make_function_callsites,
589
+ ClinicStage.POST_CALLSITES: self._stage_post_callsite_simplifications,
590
+ ClinicStage.RECOVER_VARIABLES: self._stage_recover_variables,
591
+ ClinicStage.SEMANTIC_VARIABLE_NAMING: self._stage_semantic_variable_naming,
592
+ ClinicStage.COLLECT_EXTERNS: self._stage_collect_externs,
593
+ }
594
+
595
+ for stage in sorted(stages):
596
+ if stage < self._start_stage or stage > self._end_stage or stage in self._skip_stages:
597
+ continue
598
+ stages[stage]()
599
+
600
+ # remove empty nodes from the graph
601
+ self._ail_graph = self.remove_empty_nodes(self._ail_graph)
602
+ # note that there are still edges to remove before we can structure this graph!
603
+
604
+ self.cc_graph = self.copy_graph(self._ail_graph)
605
+ return self._ail_graph
606
+
607
+ def _stage_make_return_sites(self) -> None:
608
+ self._update_progress(30.0, text="Making return sites")
609
+ if self.function.prototype is None or not isinstance(self.function.prototype.returnty, SimTypeBottom):
610
+ self._ail_graph = self._make_returns(self._ail_graph)
611
+ self._ail_graph = self._run_simplification_passes(
612
+ self._ail_graph, stage=OptimizationPassStage.BEFORE_SSA_LEVEL0_TRANSFORMATION
613
+ )
614
+
615
+ def _stage_make_function_argument_list(self) -> None:
616
+ self._update_progress(33.0, text="Making argument list")
617
+ self.arg_list = self._make_argument_list()
618
+ self.arg_vvars = self._create_function_argument_vvars(self.arg_list)
619
+ self.func_args = {arg_vvar for arg_vvar, _ in self.arg_vvars.values()}
620
+
621
+ def _stage_pre_ssa_level0_fixups(self) -> None:
622
+ # duplicate orphaned conditional jump blocks
623
+ self._ail_graph = self._duplicate_orphaned_cond_jumps(self._ail_graph)
624
+ # rewrite jmp_rax function calls
625
+ self._ail_graph = self._rewrite_jump_rax_calls(self._ail_graph)
626
+
627
+ def _stage_transform_to_ssa_level0(self) -> None:
628
+ self._update_progress(35.0, text="Transforming to partial-SSA form (registers)")
629
+ assert self.func_args is not None
630
+ self._ail_graph = self._transform_to_ssa_level0(self._ail_graph, self.func_args)
631
+
632
+ def _stage_constant_propagation(self) -> None:
633
+ # full-function constant-only propagation
634
+ self._update_progress(36.0, text="Constant propagation")
635
+ self._simplify_function(
636
+ self._ail_graph,
637
+ remove_dead_memdefs=False,
638
+ unify_variables=False,
639
+ narrow_expressions=False,
640
+ only_consts=True,
641
+ fold_callexprs_into_conditions=self._fold_callexprs_into_conditions,
642
+ max_iterations=1,
643
+ )
644
+
645
+ def _stage_track_stack_pointers(self) -> None:
646
+ self._spt = self._track_stack_pointers()
647
+
648
+ def _stage_transform_to_ssa_level1(self) -> None:
649
+ self._update_progress(37.0, text="Transforming to partial-SSA form (stack variables)")
650
+ # rewrite (qualified) stack variables into SSA form
651
+ assert self.func_args is not None
652
+ self._ail_graph = self._transform_to_ssa_level1(self._ail_graph, self.func_args)
653
+
654
+ # Run simplification passes
655
+ self._update_progress(49.0, text="Running simplifications 1.5")
656
+ self._ail_graph = self._run_simplification_passes(
657
+ self._ail_graph, stage=OptimizationPassStage.AFTER_SSA_LEVEL1_TRANSFORMATION
658
+ )
659
+
660
+ # register save area has been removed at this point - we should no longer use callee-saved registers in RDA
661
+ self._register_save_areas_removed = True
662
+ # clear the cached RDA result
663
+ self.reaching_definitions = None
664
+
665
+ def _stage_pre_ssa_level1_simplifications(self) -> None:
666
+ # Simplify blocks
667
+ # we never remove dead memory definitions before making callsites. otherwise stack arguments may go missing
668
+ # before they are recognized as stack arguments.
669
+ self._update_progress(38.0, text="Simplifying blocks 1")
670
+ self._ail_graph = self._simplify_blocks(
671
+ self._ail_graph,
672
+ stack_pointer_tracker=self._spt,
673
+ cache=self._block_simplification_cache,
674
+ preserve_vvar_ids=self._preserve_vvar_ids,
675
+ type_hints=self._type_hints,
676
+ )
677
+ self._rewrite_alloca(self._ail_graph)
678
+
679
+ # Run simplification passes
680
+ self._update_progress(40.0, text="Running simplifications 1")
681
+ self._ail_graph = self._run_simplification_passes(
682
+ self._ail_graph,
683
+ stack_pointer_tracker=self._spt,
684
+ stack_items=self.stack_items,
685
+ stage=OptimizationPassStage.AFTER_SINGLE_BLOCK_SIMPLIFICATION,
686
+ )
687
+
688
+ # Simplify the entire function for the first time
689
+ self._update_progress(45.0, text="Simplifying function 1")
690
+ self._simplify_function(
691
+ self._ail_graph,
692
+ remove_dead_memdefs=False,
693
+ unify_variables=False,
694
+ narrow_expressions=False,
695
+ fold_callexprs_into_conditions=self._fold_callexprs_into_conditions,
696
+ arg_vvars=self.arg_vvars,
697
+ )
698
+
699
+ # Run simplification passes again. there might be more chances for peephole optimizations after function-level
700
+ # simplification
701
+ self._update_progress(48.0, text="Simplifying blocks 2")
702
+ self._ail_graph = self._simplify_blocks(
703
+ self._ail_graph,
704
+ stack_pointer_tracker=self._spt,
705
+ cache=self._block_simplification_cache,
706
+ preserve_vvar_ids=self._preserve_vvar_ids,
707
+ type_hints=self._type_hints,
708
+ )
709
+
710
+ # Run simplification passes
711
+ self._update_progress(49.0, text="Running simplifications 2")
712
+ self._ail_graph = self._run_simplification_passes(
713
+ self._ail_graph, stage=OptimizationPassStage.BEFORE_SSA_LEVEL1_TRANSFORMATION
714
+ )
715
+
716
+ def _stage_post_ssa_level1_simplifications(self) -> None:
717
+ # Rust-specific; only call this on Rust binaries when we can identify language and compiler
718
+ self._ail_graph = self._rewrite_rust_probestack_call(self._ail_graph)
719
+ # Windows-specific
720
+ self._ail_graph = self._rewrite_windows_chkstk_call(self._ail_graph)
721
+
722
+ def _stage_make_function_callsites(self) -> None:
723
+ assert self.func_args is not None
724
+
725
+ # Make call-sites
726
+ self._update_progress(50.0, text="Making callsites")
727
+ _, stackarg_offsets, removed_vvar_ids = self._make_callsites(
728
+ self._ail_graph, self.func_args, stack_pointer_tracker=self._spt, preserve_vvar_ids=self._preserve_vvar_ids
729
+ )
730
+
731
+ # Run simplification passes
732
+ self._update_progress(53.0, text="Running simplifications 2")
733
+ self._ail_graph = self._run_simplification_passes(
734
+ self._ail_graph, stage=OptimizationPassStage.AFTER_MAKING_CALLSITES
735
+ )
736
+
737
+ # Simplify the entire function for the second time
738
+ self._update_progress(55.0, text="Simplifying function 2")
739
+ self._simplify_function(
740
+ self._ail_graph,
741
+ remove_dead_memdefs=self._remove_dead_memdefs,
742
+ stack_arg_offsets=stackarg_offsets,
743
+ unify_variables=True,
744
+ narrow_expressions=True,
745
+ fold_callexprs_into_conditions=self._fold_callexprs_into_conditions,
746
+ removed_vvar_ids=removed_vvar_ids,
747
+ arg_vvars=self.arg_vvars,
748
+ preserve_vvar_ids=self._preserve_vvar_ids,
749
+ )
750
+
751
+ # After global optimization, there might be more chances for peephole optimizations.
752
+ # Simplify blocks for the second time
753
+ self._update_progress(60.0, text="Simplifying blocks 3")
754
+ self._ail_graph = self._simplify_blocks(
755
+ self._ail_graph,
756
+ stack_pointer_tracker=self._spt,
757
+ cache=self._block_simplification_cache,
758
+ preserve_vvar_ids=self._preserve_vvar_ids,
759
+ type_hints=self._type_hints,
760
+ )
761
+
762
+ # Run simplification passes
763
+ self._update_progress(65.0, text="Running simplifications 3")
764
+ self._ail_graph = self._run_simplification_passes(
765
+ self._ail_graph,
766
+ stack_items=self.stack_items,
767
+ stage=OptimizationPassStage.AFTER_GLOBAL_SIMPLIFICATION,
768
+ arg_vvars=self.arg_vvars,
769
+ )
770
+
771
+ # Simplify the entire function for the third time
772
+ self._update_progress(70.0, text="Simplifying function 3")
773
+ self._simplify_function(
774
+ self._ail_graph,
775
+ remove_dead_memdefs=self._remove_dead_memdefs,
776
+ stack_arg_offsets=stackarg_offsets,
777
+ unify_variables=True,
778
+ narrow_expressions=True,
779
+ fold_callexprs_into_conditions=self._fold_callexprs_into_conditions,
780
+ arg_vvars=self.arg_vvars,
781
+ preserve_vvar_ids=self._preserve_vvar_ids,
782
+ )
783
+
784
+ self._update_progress(75.0, text="Simplifying blocks 4")
785
+ self._ail_graph = self._simplify_blocks(
786
+ self._ail_graph,
787
+ stack_pointer_tracker=self._spt,
788
+ cache=self._block_simplification_cache,
789
+ preserve_vvar_ids=self._preserve_vvar_ids,
790
+ type_hints=self._type_hints,
791
+ )
792
+
793
+ # Simplify the entire function for the fourth time
794
+ self._update_progress(78.0, text="Simplifying function 4")
795
+ self._simplify_function(
796
+ self._ail_graph,
797
+ remove_dead_memdefs=self._remove_dead_memdefs,
798
+ stack_arg_offsets=stackarg_offsets,
799
+ unify_variables=True,
800
+ narrow_expressions=True,
801
+ fold_callexprs_into_conditions=self._fold_callexprs_into_conditions,
802
+ arg_vvars=self.arg_vvars,
803
+ preserve_vvar_ids=self._preserve_vvar_ids,
804
+ )
805
+
806
+ def _stage_post_callsite_simplifications(self) -> None:
807
+ self.arg_list = []
808
+ self.vvar_to_vvar = {}
809
+ self.copied_var_ids = set()
810
+
811
+ self._update_progress(79.0, text="Running simplifications 4")
812
+ self._ail_graph = self._run_simplification_passes(
813
+ self._ail_graph, stack_items=self.stack_items, stage=OptimizationPassStage.BEFORE_VARIABLE_RECOVERY
814
+ )
815
+
816
+ assert self.arg_vvars is not None
817
+
818
+ # update arg_list
819
+ for idx in sorted(self.arg_vvars):
820
+ self.arg_list.append(self.arg_vvars[idx][1])
821
+
822
+ # Get virtual variable mapping that can de-phi the SSA representation
823
+ self.vvar_to_vvar, self.copied_var_ids = self._collect_dephi_vvar_mapping_and_rewrite_blocks(
824
+ self._ail_graph, self.arg_vvars
825
+ )
826
+
827
+ def _stage_recover_variables(self) -> None:
828
+ assert self.arg_list is not None and self.arg_vvars is not None and self.vvar_to_vvar is not None
829
+
830
+ # Recover variables on AIL blocks
831
+ self._update_progress(80.0, text="Recovering variables")
832
+ variable_kb = self._recover_and_link_variables(
833
+ self._ail_graph, self.arg_list, self.arg_vvars, self.vvar_to_vvar, self._type_hints
834
+ )
835
+
836
+ # Run simplification passes
837
+ self._update_progress(85.0, text="Running simplifications 4")
838
+ self._ail_graph = self._run_simplification_passes(
839
+ self._ail_graph,
840
+ stage=OptimizationPassStage.AFTER_VARIABLE_RECOVERY,
841
+ avoid_vvar_ids=self.copied_var_ids,
842
+ )
843
+
844
+ # Make function prototype
845
+ self._update_progress(90.0, text="Making function prototype")
846
+ self._make_function_prototype(self.arg_list, variable_kb)
847
+
848
+ self.variable_kb = variable_kb
849
+
850
+ def _stage_semantic_variable_naming(self) -> None:
851
+ """
852
+ Apply semantic-based variable naming.
853
+
854
+ This stage analyzes the AIL graph for semantic patterns and renames variables accordingly.
855
+ """
856
+
857
+ if self.variable_kb is None:
858
+ l.debug("variable_kb is None, skipping semantic variable naming")
859
+ return
860
+
861
+ self._update_progress(91.0, text="Applying semantic variable naming")
862
+
863
+ # Get the variable manager for this function
864
+ var_manager = self.variable_kb.variables[self.function.addr]
865
+
866
+ # Find the entry node
867
+ entry_node: ailment.Block | None = None
868
+ for node in self._ail_graph:
869
+ if (node.addr, node.idx) == self.entry_node_addr:
870
+ entry_node = node
871
+ break
872
+
873
+ assert entry_node is not None
874
+
875
+ # Run all semantic naming patterns via the orchestrator
876
+ orchestrator = SemanticNamingOrchestrator(self._ail_graph, var_manager, self.kb.functions, entry_node)
877
+ var_name_mapping = orchestrator.analyze()
878
+ l.debug("Semantic naming renamed %d variables", len(var_name_mapping))
879
+
880
+ def _stage_collect_externs(self) -> None:
881
+ self.externs = self._collect_externs(self._ail_graph, self.variable_kb)
882
+
883
+ def _analyze_for_data_refs(self):
884
+ # Remove alignment blocks
885
+ self._update_progress(5.0, text="Removing alignment blocks")
886
+ self._remove_alignment_blocks()
887
+
888
+ # if the graph is empty, don't continue
889
+ if not self._func_graph:
890
+ return
891
+
892
+ # initialize the AIL conversion manager
893
+ self._ail_manager = ailment.Manager(arch=self.project.arch)
894
+
895
+ # Track stack pointers
896
+ self._update_progress(15.0, text="Tracking stack pointers")
897
+ spt = self._track_stack_pointers()
898
+
899
+ # Convert VEX blocks to AIL blocks and then simplify them
900
+
901
+ self._update_progress(20.0, text="Converting VEX to AIL")
902
+ self._convert_all()
903
+
904
+ # there must be at least one Load or one Store
905
+ assert self._blocks_by_addr_and_size is not None
906
+ found_load_or_store = False
907
+ for ail_block in self._blocks_by_addr_and_size.values():
908
+ for stmt in ail_block.statements:
909
+ if isinstance(stmt, ailment.Stmt.Store):
910
+ found_load_or_store = True
911
+ break
912
+ if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.Load):
913
+ found_load_or_store = True
914
+ break
915
+ if not found_load_or_store:
916
+ self.data_refs = {}
917
+ return
918
+
919
+ ail_graph = self._make_ailgraph()
920
+ self._remove_redundant_jump_blocks(ail_graph)
921
+
922
+ # full-function constant-only propagation
923
+ self._update_progress(33.0, text="Constant propagation")
924
+ self._simplify_function(
925
+ ail_graph,
926
+ remove_dead_memdefs=False,
927
+ unify_variables=False,
928
+ narrow_expressions=False,
929
+ only_consts=True,
930
+ fold_callexprs_into_conditions=self._fold_callexprs_into_conditions,
931
+ max_iterations=1,
932
+ )
933
+
934
+ # cached block-level reaching definition analysis results and propagator results
935
+ block_simplification_cache: dict[ailment.Block, NamedTuple] | None = {}
936
+
937
+ # Simplify blocks
938
+ # we never remove dead memory definitions before making callsites. otherwise stack arguments may go missing
939
+ # before they are recognized as stack arguments.
940
+ self._update_progress(35.0, text="Simplifying blocks 1")
941
+ ail_graph = self._simplify_blocks(ail_graph, stack_pointer_tracker=spt, cache=block_simplification_cache)
942
+
943
+ # Simplify the entire function for the first time
944
+ self._update_progress(45.0, text="Simplifying function 1")
945
+ self._simplify_function(
946
+ ail_graph,
947
+ remove_dead_memdefs=False,
948
+ unify_variables=False,
949
+ narrow_expressions=False,
950
+ fold_callexprs_into_conditions=False,
951
+ rewrite_ccalls=False,
952
+ max_iterations=1,
953
+ )
954
+
955
+ # clear _blocks_by_addr_and_size so no one can use it again
956
+ # TODO: Totally remove this dict
957
+ self._blocks_by_addr_and_size = None
958
+
959
+ self.graph = ail_graph
960
+ self.arg_list = None
961
+ self.variable_kb = None
962
+ self.cc_graph = None
963
+ self.externs = set()
964
+ self.data_refs: dict[int, list[DataRefDesc]] = self._collect_data_refs(ail_graph)
965
+
966
+ @staticmethod
967
+ def _copy_graph(graph: networkx.DiGraph) -> networkx.DiGraph:
968
+ """
969
+ Copy AIL Graph.
970
+
971
+ :return: A copy of the AIl graph.
972
+ """
973
+ graph_copy = networkx.DiGraph()
974
+ block_mapping = {}
975
+ # copy all blocks
976
+ for block in graph.nodes():
977
+ new_block = copy.copy(block)
978
+ new_stmts = copy.copy(block.statements)
979
+ new_block.statements = new_stmts
980
+ block_mapping[block] = new_block
981
+ graph_copy.add_node(new_block)
982
+
983
+ # copy all edges
984
+ for src, dst, data in graph.edges(data=True):
985
+ new_src = block_mapping[src]
986
+ new_dst = block_mapping[dst]
987
+ graph_copy.add_edge(new_src, new_dst, **data)
988
+ return graph_copy
989
+
990
+ def copy_graph(self, graph=None) -> networkx.DiGraph:
991
+ return self._copy_graph(graph or self.graph) # type:ignore
992
+
993
+ @timethis
994
+ def _set_function_graph(self):
995
+ self._func_graph = self.function.graph_ex(exception_edges=self._exception_edges)
996
+
997
+ @timethis
998
+ def _remove_alignment_blocks(self):
999
+ """
1000
+ Alignment blocks are basic blocks that only consist of nops. They should not be included in the graph.
1001
+ """
1002
+ assert self._func_graph is not None
1003
+ for node in list(self._func_graph.nodes()):
1004
+ if self._func_graph.in_degree(node) == 0 and CFGBase._is_noop_block(
1005
+ self.project.arch, self.project.factory.block(node.addr, node.size)
1006
+ ):
1007
+ if (node.addr, None) == self.entry_node_addr:
1008
+ # this is the entry node. after removing this node, the new entry node will be its successor
1009
+ if self._func_graph.out_degree[node] == 1:
1010
+ succ = next(iter(self._func_graph.successors(node)))
1011
+ self.entry_node_addr = succ.addr, None
1012
+ else:
1013
+ # we just don't remove this node...
1014
+ continue
1015
+ self._func_graph.remove_node(node)
1016
+
1017
+ @timethis
1018
+ def _recover_calling_conventions(self, func_graph=None) -> None:
1019
+ """
1020
+ Examine the calling convention and function prototype for each function called. For functions with missing
1021
+ calling conventions or function prototypes, analyze each *call site* and recover the calling convention and
1022
+ function prototype of the callee function.
1023
+
1024
+ :return: None
1025
+ """
1026
+
1027
+ attempted_funcs: set[int] = set()
1028
+
1029
+ for node in self.function.transition_graph:
1030
+ if (
1031
+ isinstance(node, BlockNode)
1032
+ and node.addr != self.function.addr
1033
+ and self.kb.functions.contains_addr(node.addr)
1034
+ ):
1035
+ # tail jumps
1036
+ target_func = self.kb.functions.get_by_addr(node.addr)
1037
+ elif isinstance(node, Function):
1038
+ target_func = node
1039
+ else:
1040
+ # TODO: Enable call-site analysis for indirect calls
1041
+ continue
1042
+
1043
+ if target_func.addr in attempted_funcs:
1044
+ continue
1045
+ attempted_funcs.add(target_func.addr)
1046
+
1047
+ # case 0: the calling convention and prototype are available
1048
+ if target_func.calling_convention is not None and target_func.prototype is not None:
1049
+ continue
1050
+
1051
+ call_sites = []
1052
+ for pred, _, data in self.function.transition_graph.in_edges(node, data=True):
1053
+ if data.get("type", None) != "return":
1054
+ call_sites.append(pred)
1055
+ # case 1: calling conventions and prototypes are available at every single call site
1056
+ if call_sites and all(self.kb.callsite_prototypes.has_prototype(callsite.addr) for callsite in call_sites):
1057
+ continue
1058
+
1059
+ # case 2: the callee is a SimProcedure
1060
+ if target_func.is_simprocedure:
1061
+ cc = self.project.analyses.CallingConvention(target_func, fail_fast=self._fail_fast) # type: ignore
1062
+ if cc.cc is not None and cc.prototype is not None:
1063
+ target_func.calling_convention = cc.cc
1064
+ target_func.prototype = cc.prototype
1065
+ target_func.prototype_libname = cc.prototype_libname
1066
+ continue
1067
+
1068
+ # case 3: the callee is a PLT function
1069
+ if target_func.is_plt:
1070
+ cc = self.project.analyses.CallingConvention(target_func, fail_fast=self._fail_fast) # type: ignore
1071
+ if cc.cc is not None and cc.prototype is not None:
1072
+ target_func.calling_convention = cc.cc
1073
+ target_func.prototype = cc.prototype
1074
+ target_func.prototype_libname = cc.prototype_libname
1075
+ continue
1076
+
1077
+ # case 4: fall back to call site analysis
1078
+ for callsite in call_sites:
1079
+ if self.kb.callsite_prototypes.has_prototype(callsite.addr):
1080
+ continue
1081
+
1082
+ # parse the call instruction address from the edge
1083
+ callsite_ins_addr = None
1084
+ edge_data = [
1085
+ data
1086
+ for src, dst, data in self.function.transition_graph.in_edges(node, data=True)
1087
+ if src is callsite
1088
+ ]
1089
+ if len(edge_data) == 1:
1090
+ callsite_ins_addr = edge_data[0].get("ins_addr", None)
1091
+ if callsite_ins_addr is None:
1092
+ # parse the block...
1093
+ callsite_block = self.project.factory.block(callsite.addr, size=callsite.size)
1094
+ if self.project.arch.branch_delay_slot:
1095
+ if callsite_block.instructions < 2:
1096
+ continue
1097
+ callsite_ins_addr = callsite_block.instruction_addrs[-2]
1098
+ else:
1099
+ if callsite_block.instructions == 0:
1100
+ continue
1101
+ callsite_ins_addr = callsite_block.instruction_addrs[-1]
1102
+
1103
+ cc = self.project.analyses.CallingConvention(
1104
+ None,
1105
+ analyze_callsites=True,
1106
+ caller_func_addr=self.function.addr,
1107
+ callsite_block_addr=callsite.addr,
1108
+ callsite_insn_addr=callsite_ins_addr,
1109
+ func_graph=func_graph,
1110
+ fail_fast=self._fail_fast, # type:ignore
1111
+ )
1112
+
1113
+ if cc.cc is not None and cc.prototype is not None:
1114
+ self.kb.callsite_prototypes.set_prototype(callsite.addr, cc.cc, cc.prototype)
1115
+ if func_graph is not None and cc.prototype.returnty is not None:
1116
+ # patch the AIL call statement if we can find one
1117
+ callsite_ail_block: ailment.Block | None = next(
1118
+ iter(bb for bb in func_graph if bb.addr == callsite.addr), None
1119
+ )
1120
+ if callsite_ail_block is not None and callsite_ail_block.statements:
1121
+ last_stmt = callsite_ail_block.statements[-1]
1122
+ if (
1123
+ isinstance(last_stmt, ailment.Stmt.Call)
1124
+ and last_stmt.ret_expr is None
1125
+ and isinstance(cc.cc.RETURN_VAL, SimRegArg)
1126
+ ):
1127
+ reg_offset, reg_size = self.project.arch.registers[cc.cc.RETURN_VAL.reg_name]
1128
+ last_stmt.ret_expr = ailment.Expr.Register(
1129
+ None,
1130
+ None,
1131
+ reg_offset,
1132
+ reg_size * 8,
1133
+ ins_addr=callsite_ins_addr,
1134
+ reg_name=cc.cc.RETURN_VAL.reg_name,
1135
+ )
1136
+ last_stmt.bits = reg_size * 8
1137
+
1138
+ # finally, recover the calling convention of the current function
1139
+ if self.function.prototype is None or self.function.calling_convention is None:
1140
+ self.project.analyses.CompleteCallingConventions(
1141
+ fail_fast=self._fail_fast, # type: ignore
1142
+ recover_variables=True,
1143
+ prioritize_func_addrs=[self.function.addr],
1144
+ skip_other_funcs=True,
1145
+ skip_signature_matched_functions=False,
1146
+ func_graphs={self.function.addr: func_graph} if func_graph is not None else None,
1147
+ )
1148
+
1149
+ @timethis
1150
+ def _track_stack_pointers(self):
1151
+ """
1152
+ For each instruction, track its stack pointer offset and stack base pointer offset.
1153
+
1154
+ :return: None
1155
+ """
1156
+
1157
+ regs = {self.project.arch.sp_offset}
1158
+ initial_reg_values = {
1159
+ self.project.arch.sp_offset: OffsetVal(
1160
+ Register(self.project.arch.sp_offset, self.project.arch.bits), self._sp_shift
1161
+ )
1162
+ }
1163
+ if hasattr(self.project.arch, "bp_offset") and self.project.arch.bp_offset is not None:
1164
+ regs.add(self.project.arch.bp_offset)
1165
+ initial_reg_values[self.project.arch.bp_offset] = OffsetVal(
1166
+ Register(self.project.arch.bp_offset, self.project.arch.bits), self._sp_shift
1167
+ )
1168
+
1169
+ regs |= self._find_regs_compared_against_sp(self._func_graph)
1170
+
1171
+ spt = self.project.analyses.StackPointerTracker(
1172
+ self.function,
1173
+ regs,
1174
+ fail_fast=self._fail_fast,
1175
+ track_memory=self._sp_tracker_track_memory,
1176
+ cross_insn_opt=False,
1177
+ initial_reg_values=initial_reg_values,
1178
+ )
1179
+
1180
+ if spt.inconsistent_for(self.project.arch.sp_offset):
1181
+ l.warning("Inconsistency found during stack pointer tracking. Decompilation results might be incorrect.")
1182
+ return spt
1183
+
1184
+ @timethis
1185
+ def _convert_all(self):
1186
+ """
1187
+ Convert all VEX blocks in the function graph to AIL blocks, and fill self._blocks.
1188
+
1189
+ :return: None
1190
+ """
1191
+ assert self._func_graph is not None
1192
+ assert self._blocks_by_addr_and_size is not None
1193
+
1194
+ for block_node in self._func_graph.nodes():
1195
+ ail_block = self._convert(block_node)
1196
+
1197
+ if type(ail_block) is ailment.Block:
1198
+ # remove constant pc assignments
1199
+ ail_block.statements = [
1200
+ stmt
1201
+ for stmt in ail_block.statements
1202
+ if not (
1203
+ isinstance(stmt, ailment.Stmt.Assignment)
1204
+ and isinstance(stmt.dst, ailment.Expr.Register)
1205
+ and stmt.dst.reg_offset == self.project.arch.ip_offset
1206
+ and isinstance(stmt.src, ailment.Expr.Const)
1207
+ )
1208
+ ]
1209
+
1210
+ self._blocks_by_addr_and_size[(block_node.addr, block_node.size)] = ail_block
1211
+
1212
+ def _convert(self, block_node):
1213
+ """
1214
+ Convert a BlockNode to an AIL block.
1215
+
1216
+ :param block_node: A BlockNode instance.
1217
+ :return: A converted AIL block.
1218
+ :rtype: ailment.Block
1219
+ """
1220
+
1221
+ if type(block_node) is not BlockNode:
1222
+ return block_node
1223
+
1224
+ if block_node.size == 0:
1225
+ return ailment.Block(block_node.addr, 0, statements=[])
1226
+
1227
+ block = self.project.factory.block(block_node.addr, block_node.size, cross_insn_opt=False)
1228
+ converted = self._convert_vex(block)
1229
+
1230
+ # architecture-specific setup
1231
+ if block.addr == self.function.addr and self.project.arch.name in {"X86", "AMD64"}:
1232
+ # setup dflag; this is a hack for most sane ABIs. we may move this logic elsewhere if there are adversarial
1233
+ # binaries that mess with dflags and pass them across functions
1234
+ dflag_offset, dflag_size = self.project.arch.registers["d"]
1235
+ dflag = ailment.Expr.Register(
1236
+ self._ail_manager.next_atom(),
1237
+ None,
1238
+ dflag_offset,
1239
+ dflag_size * self.project.arch.byte_width,
1240
+ ins_addr=block.addr,
1241
+ )
1242
+ forward = ailment.Expr.Const(
1243
+ self._ail_manager.next_atom(), None, 1, dflag_size * self.project.arch.byte_width, ins_addr=block.addr
1244
+ )
1245
+ dflag_assignment = ailment.Stmt.Assignment(
1246
+ self._ail_manager.next_atom(), dflag, forward, ins_addr=block.addr
1247
+ )
1248
+ converted.statements.insert(0, dflag_assignment)
1249
+
1250
+ return converted
1251
+
1252
+ def _convert_vex(self, block):
1253
+ if block.vex.jumpkind not in {"Ijk_Call", "Ijk_Boring", "Ijk_Ret"} and not block.vex.jumpkind.startswith(
1254
+ "Ijk_Sys"
1255
+ ):
1256
+ # we don't support lifting this block. use a dummy block instead
1257
+ dirty_expr = ailment.Expr.DirtyExpression(
1258
+ self._ail_manager.next_atom,
1259
+ f"Unsupported jumpkind {block.vex.jumpkind} at address {block.addr}",
1260
+ [],
1261
+ bits=0,
1262
+ )
1263
+ statements: list[ailment.Statement] = [
1264
+ ailment.Stmt.DirtyStatement(
1265
+ self._ail_manager.next_atom(),
1266
+ dirty_expr,
1267
+ ins_addr=block.addr,
1268
+ )
1269
+ ]
1270
+ return ailment.Block(block.addr, block.size, statements=statements)
1271
+
1272
+ return ailment.IRSBConverter.convert(block.vex, self._ail_manager)
1273
+
1274
+ @timethis
1275
+ def _replace_single_target_indirect_transitions(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
1276
+ """
1277
+ Remove single-target indirect jumps and calls and replace them with direct jumps or calls.
1278
+ """
1279
+ if self._cfg is None:
1280
+ return ail_graph
1281
+
1282
+ for block in ail_graph.nodes():
1283
+ if not block.statements:
1284
+ continue
1285
+ last_stmt = block.statements[-1]
1286
+ if isinstance(last_stmt, ailment.Stmt.Call) and not isinstance(last_stmt.target, ailment.Expr.Const):
1287
+ # indirect call
1288
+ # consult CFG to see if this is a call with a single successor
1289
+ node = self._cfg.get_any_node(block.addr)
1290
+ if node is None:
1291
+ continue
1292
+ successors = [
1293
+ node
1294
+ for node, jk in self._cfg.get_successors_and_jumpkinds(node)
1295
+ if jk == "Ijk_Call" or jk.startswith("Ijk_Sys")
1296
+ ]
1297
+ if len(successors) == 1:
1298
+ succ_addr = successors[0].addr
1299
+ if not self.project.is_hooked(succ_addr) or not isinstance(
1300
+ self.project.hooked_by(successors[0].addr), UnresolvableCallTarget
1301
+ ):
1302
+ # found a single successor - replace the last statement
1303
+ assert isinstance(last_stmt.target, ailment.Expr.Expression) # not a string
1304
+ new_last_stmt = last_stmt.copy()
1305
+ assert isinstance(successors[0].addr, int)
1306
+ new_last_stmt.target = ailment.Expr.Const(None, None, successors[0].addr, last_stmt.target.bits)
1307
+ block.statements[-1] = new_last_stmt
1308
+
1309
+ elif isinstance(last_stmt, ailment.Stmt.Jump) and not isinstance(last_stmt.target, ailment.Expr.Const):
1310
+ # indirect jump
1311
+ # consult CFG to see if there is a jump with a single successor
1312
+ node = self._cfg.get_any_node(block.addr)
1313
+ if node is None:
1314
+ continue
1315
+ successors = self._cfg.get_successors(node, excluding_fakeret=True, jumpkind="Ijk_Boring")
1316
+ if len(successors) == 1 and not isinstance(
1317
+ self.project.hooked_by(successors[0].addr), UnresolvableJumpTarget
1318
+ ):
1319
+ # found a single successor - replace the last statement
1320
+ new_last_stmt = last_stmt.copy()
1321
+ assert isinstance(successors[0].addr, int)
1322
+ new_last_stmt.target = ailment.Expr.Const(None, None, successors[0].addr, last_stmt.target.bits)
1323
+ block.statements[-1] = new_last_stmt
1324
+
1325
+ return ail_graph
1326
+
1327
+ @timethis
1328
+ def _replace_tail_jumps_with_calls(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
1329
+ """
1330
+ Rewrite tail jumps to functions as call statements.
1331
+ """
1332
+ for block in list(ail_graph.nodes()):
1333
+ if ail_graph.out_degree[block] > 1:
1334
+ continue
1335
+
1336
+ last_stmt = block.statements[-1]
1337
+ if isinstance(last_stmt, ailment.Stmt.Jump):
1338
+ targets = [last_stmt.target]
1339
+ replace_last_stmt = True
1340
+ elif isinstance(last_stmt, ailment.Stmt.ConditionalJump):
1341
+ targets = [last_stmt.true_target, last_stmt.false_target]
1342
+ replace_last_stmt = False
1343
+ else:
1344
+ continue
1345
+
1346
+ for target in targets:
1347
+ if not isinstance(target, ailment.Const) or not self.kb.functions.contains_addr(target.value):
1348
+ continue
1349
+
1350
+ target_func = self.kb.functions.get_by_addr(target.value)
1351
+
1352
+ ret_reg_offset = self.project.arch.ret_offset
1353
+ if target_func.returning and ret_reg_offset is not None:
1354
+ ret_expr = ailment.Expr.Register(
1355
+ None,
1356
+ None,
1357
+ ret_reg_offset,
1358
+ self.project.arch.bits,
1359
+ reg_name=self.project.arch.translate_register_name(ret_reg_offset, size=self.project.arch.bits),
1360
+ **target.tags,
1361
+ )
1362
+ else:
1363
+ ret_expr = None
1364
+
1365
+ call_stmt = ailment.Stmt.Call(
1366
+ None,
1367
+ target.copy(),
1368
+ calling_convention=None, # target_func.calling_convention,
1369
+ prototype=None, # target_func.prototype,
1370
+ ret_expr=ret_expr,
1371
+ **last_stmt.tags,
1372
+ )
1373
+
1374
+ if replace_last_stmt:
1375
+ call_block = block
1376
+ block.statements[-1] = call_stmt
1377
+ else:
1378
+ call_block = ailment.Block(self.new_block_addr(), 1, statements=[call_stmt])
1379
+ ail_graph.add_edge(block, call_block)
1380
+ target.value = call_block.addr
1381
+
1382
+ if target_func.returning:
1383
+ ret_stmt = ailment.Stmt.Return(None, [], **last_stmt.tags)
1384
+ ret_block = ailment.Block(self.new_block_addr(), 1, statements=[ret_stmt])
1385
+ ail_graph.add_edge(call_block, ret_block, type="fake_return")
1386
+
1387
+ return ail_graph
1388
+
1389
+ @timethis
1390
+ def _fix_special_call_calling_conventions(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
1391
+ """
1392
+ Fix the calling convention for special function calls.
1393
+ """
1394
+ for block in list(ail_graph.nodes()):
1395
+ last_stmt = block.statements[-1]
1396
+ if isinstance(last_stmt, ailment.Stmt.Call) and isinstance(last_stmt.target, ailment.Expr.Const):
1397
+ target = last_stmt.target.value
1398
+ else:
1399
+ continue
1400
+
1401
+ if not self.kb.functions.contains_addr(target):
1402
+ continue
1403
+ target_func = self.kb.functions.get_by_addr(target)
1404
+ if target_func.name == "_security_check_cookie" and self.project.arch.name in {"X86", "AMD64"}:
1405
+ arg = SimRegArg("ecx", 32) if self.project.arch.bits == 32 else SimRegArg("rcx", 64)
1406
+ arg_offset, arg_bits = self.project.arch.registers[arg.reg_name]
1407
+ arg_expr = ailment.Expr.Register(
1408
+ self._ail_manager.next_atom(),
1409
+ None,
1410
+ arg_offset,
1411
+ arg_bits * self.project.arch.byte_width,
1412
+ **last_stmt.tags,
1413
+ )
1414
+ IntCls = SimTypeInt if self.project.arch.bits == 32 else SimTypeLongLong
1415
+ call_stmt = ailment.Stmt.Call(
1416
+ None,
1417
+ last_stmt.target.copy(),
1418
+ calling_convention=SimCCUsercall(self.project.arch, [arg], []),
1419
+ prototype=SimTypeFunction([IntCls(signed=False)], SimTypeBottom(label="void")).with_arch(
1420
+ self.project.arch
1421
+ ),
1422
+ args=[arg_expr],
1423
+ ret_expr=None,
1424
+ is_prototype_guessed=False,
1425
+ **last_stmt.tags,
1426
+ )
1427
+ block.statements[-1] = call_stmt
1428
+
1429
+ return ail_graph
1430
+
1431
+ def _apply_callsite_prototype_and_calling_convention(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
1432
+ for block in ail_graph.nodes():
1433
+ if not block.statements:
1434
+ continue
1435
+
1436
+ last_stmt = block.statements[-1]
1437
+ if not isinstance(last_stmt, ailment.Stmt.Call):
1438
+ continue
1439
+
1440
+ cc = last_stmt.calling_convention
1441
+ prototype = last_stmt.prototype
1442
+ if cc and prototype:
1443
+ continue
1444
+
1445
+ # manually-specified call-site prototype
1446
+ has_callsite_prototype = self.kb.callsite_prototypes.has_prototype(block.addr)
1447
+ if has_callsite_prototype:
1448
+ manually_specified = self.kb.callsite_prototypes.is_prototype_manual(block.addr)
1449
+ if manually_specified:
1450
+ cc = self.kb.callsite_prototypes.get_cc(block.addr)
1451
+ prototype = self.kb.callsite_prototypes.get_prototype(block.addr)
1452
+
1453
+ # function-specific prototype
1454
+ func = None
1455
+ if cc is None or prototype is None:
1456
+ target = None
1457
+ if isinstance(last_stmt.target, ailment.Expr.Const):
1458
+ target = last_stmt.target.value
1459
+
1460
+ if target is not None and target in self.kb.functions:
1461
+ # function-specific logic when the calling target is known
1462
+ func = self.kb.functions[target]
1463
+ if func.prototype is None:
1464
+ func.find_declaration()
1465
+ cc = func.calling_convention
1466
+ prototype = func.prototype
1467
+
1468
+ # automatically recovered call-site prototype
1469
+ if (cc is None or prototype is None) and has_callsite_prototype:
1470
+ cc = self.kb.callsite_prototypes.get_cc(block.addr)
1471
+ prototype = self.kb.callsite_prototypes.get_prototype(block.addr)
1472
+
1473
+ # ensure the prototype has been resolved
1474
+ if prototype is not None and func is not None:
1475
+ # make sure the function prototype is resolved.
1476
+ # TODO: Cache resolved function prototypes globally
1477
+ prototype_libname = func.prototype_libname
1478
+ if prototype_libname is not None:
1479
+ prototype = dereference_simtype_by_lib(prototype, prototype_libname)
1480
+
1481
+ if cc is None:
1482
+ l.warning("Call site %#x (callee %s) has an unknown calling convention.", block.addr, repr(func))
1483
+
1484
+ new_last_stmt = last_stmt.copy()
1485
+ new_last_stmt.calling_convention = cc
1486
+ new_last_stmt.prototype = prototype
1487
+ new_last_stmt.tags["is_prototype_guessed"] = True
1488
+ if func is not None:
1489
+ new_last_stmt.tags["is_prototype_guessed"] = func.is_prototype_guessed
1490
+ block.statements[-1] = new_last_stmt
1491
+
1492
+ return ail_graph
1493
+
1494
+ @timethis
1495
+ def _make_ailgraph(self) -> networkx.DiGraph:
1496
+ return self._function_graph_to_ail_graph(self._func_graph)
1497
+
1498
+ @timethis
1499
+ def _simplify_blocks(
1500
+ self,
1501
+ ail_graph: networkx.DiGraph,
1502
+ stack_pointer_tracker=None,
1503
+ cache: dict[ailment.Block, NamedTuple] | None = None,
1504
+ preserve_vvar_ids: set[int] | None = None,
1505
+ type_hints: list[tuple[atoms.VirtualVariable | atoms.MemoryLocation, str]] | None = None,
1506
+ ):
1507
+ """
1508
+ Simplify all blocks in self._blocks.
1509
+
1510
+ :param ail_graph: The AIL function graph.
1511
+ :param stack_pointer_tracker: The RegisterDeltaTracker analysis instance.
1512
+ :param cache: A block-level cache that stores reaching definition analysis results and
1513
+ propagation results.
1514
+ :return: None
1515
+ """
1516
+
1517
+ blocks_by_addr_and_idx: dict[tuple[int, int | None], ailment.Block] = {}
1518
+
1519
+ for ail_block in ail_graph.nodes():
1520
+ simplified = self._simplify_block(
1521
+ ail_block,
1522
+ stack_pointer_tracker=stack_pointer_tracker,
1523
+ cache=cache,
1524
+ preserve_vvar_ids=preserve_vvar_ids,
1525
+ type_hints=type_hints,
1526
+ )
1527
+ key = ail_block.addr, ail_block.idx
1528
+ blocks_by_addr_and_idx[key] = simplified
1529
+
1530
+ # update blocks_map to allow node_addr to node lookup
1531
+ def _replace_node_handler(node):
1532
+ key = node.addr, node.idx
1533
+ if key in blocks_by_addr_and_idx:
1534
+ return blocks_by_addr_and_idx[key]
1535
+ return None
1536
+
1537
+ AILGraphWalker(ail_graph, _replace_node_handler, replace_nodes=True).walk()
1538
+
1539
+ return ail_graph
1540
+
1541
+ def _simplify_block(
1542
+ self,
1543
+ ail_block,
1544
+ stack_pointer_tracker=None,
1545
+ cache=None,
1546
+ preserve_vvar_ids: set[int] | None = None,
1547
+ type_hints: list[tuple[atoms.VirtualVariable | atoms.MemoryLocation, str]] | None = None,
1548
+ ):
1549
+ """
1550
+ Simplify a single AIL block.
1551
+
1552
+ :param ailment.Block ail_block: The AIL block to simplify.
1553
+ :param stack_pointer_tracker: The RegisterDeltaTracker analysis instance.
1554
+ :return: A simplified AIL block.
1555
+ """
1556
+
1557
+ cached_rd, cached_prop = None, None
1558
+ cache_item = None
1559
+ cache_key = ail_block.addr, ail_block.idx
1560
+ if cache:
1561
+ cache_item = cache.get(cache_key, None)
1562
+ if cache_item:
1563
+ # cache hit
1564
+ cached_rd = cache_item.rd
1565
+ cached_prop = cache_item.prop
1566
+
1567
+ simp = self.project.analyses.AILBlockSimplifier(
1568
+ ail_block,
1569
+ self.function.addr,
1570
+ fail_fast=self._fail_fast,
1571
+ stack_pointer_tracker=stack_pointer_tracker,
1572
+ peephole_optimizations=self.peephole_optimizations,
1573
+ cached_reaching_definitions=cached_rd,
1574
+ cached_propagator=cached_prop,
1575
+ preserve_vvar_ids=preserve_vvar_ids,
1576
+ type_hints=type_hints,
1577
+ )
1578
+ # update the cache
1579
+ if cache is not None:
1580
+ if cache_item:
1581
+ del cache[cache_key]
1582
+ cache[cache_key] = BlockCache(simp._reaching_definitions, simp._propagator)
1583
+ return simp.result_block
1584
+
1585
+ @timethis
1586
+ def _simplify_function(
1587
+ self,
1588
+ ail_graph,
1589
+ remove_dead_memdefs=False,
1590
+ stack_arg_offsets=None,
1591
+ unify_variables=False,
1592
+ max_iterations: int = 8,
1593
+ narrow_expressions=False,
1594
+ only_consts=False,
1595
+ fold_callexprs_into_conditions=False,
1596
+ rewrite_ccalls=True,
1597
+ rename_ccalls=True,
1598
+ removed_vvar_ids: set[int] | None = None,
1599
+ arg_vvars: dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]] | None = None,
1600
+ preserve_vvar_ids: set[int] | None = None,
1601
+ ) -> None:
1602
+ """
1603
+ Simplify the entire function until it reaches a fixed point.
1604
+ """
1605
+
1606
+ for idx in range(max_iterations):
1607
+ simplified = self._simplify_function_once(
1608
+ ail_graph,
1609
+ remove_dead_memdefs=remove_dead_memdefs,
1610
+ unify_variables=unify_variables,
1611
+ stack_arg_offsets=stack_arg_offsets,
1612
+ # only narrow once
1613
+ narrow_expressions=narrow_expressions and idx == 0,
1614
+ only_consts=only_consts,
1615
+ fold_callexprs_into_conditions=fold_callexprs_into_conditions,
1616
+ rewrite_ccalls=rewrite_ccalls,
1617
+ rename_ccalls=rename_ccalls,
1618
+ removed_vvar_ids=removed_vvar_ids,
1619
+ arg_vvars=arg_vvars,
1620
+ preserve_vvar_ids=preserve_vvar_ids,
1621
+ )
1622
+ if not simplified:
1623
+ break
1624
+
1625
+ @timethis
1626
+ def _simplify_function_once(
1627
+ self,
1628
+ ail_graph,
1629
+ remove_dead_memdefs=False,
1630
+ stack_arg_offsets=None,
1631
+ unify_variables=False,
1632
+ narrow_expressions=False,
1633
+ only_consts=False,
1634
+ fold_callexprs_into_conditions=False,
1635
+ rewrite_ccalls=True,
1636
+ rename_ccalls=True,
1637
+ removed_vvar_ids: set[int] | None = None,
1638
+ arg_vvars: dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]] | None = None,
1639
+ preserve_vvar_ids: set[int] | None = None,
1640
+ ):
1641
+ """
1642
+ Simplify the entire function once.
1643
+
1644
+ :return: None
1645
+ """
1646
+
1647
+ simp = self.project.analyses[AILSimplifier].prep(
1648
+ fail_fast=self._fail_fast,
1649
+ )(
1650
+ self.function,
1651
+ func_graph=ail_graph,
1652
+ remove_dead_memdefs=remove_dead_memdefs,
1653
+ unify_variables=unify_variables,
1654
+ stack_arg_offsets=stack_arg_offsets,
1655
+ ail_manager=self._ail_manager,
1656
+ gp=self.function.info.get("gp", None) if self.project.arch.name in {"MIPS32", "MIPS64"} else None,
1657
+ narrow_expressions=narrow_expressions,
1658
+ only_consts=only_consts,
1659
+ fold_callexprs_into_conditions=fold_callexprs_into_conditions,
1660
+ use_callee_saved_regs_at_return=not self._register_save_areas_removed,
1661
+ rewrite_ccalls=rewrite_ccalls,
1662
+ rename_ccalls=rename_ccalls,
1663
+ removed_vvar_ids=removed_vvar_ids,
1664
+ arg_vvars=arg_vvars,
1665
+ secondary_stackvars=self.secondary_stackvars,
1666
+ avoid_vvar_ids=preserve_vvar_ids,
1667
+ )
1668
+ # cache the simplifier's RDA analysis
1669
+ self.reaching_definitions = simp._reaching_definitions
1670
+
1671
+ # the function graph has been updated at this point
1672
+ return simp.simplified
1673
+
1674
+ @timethis
1675
+ def _run_simplification_passes(
1676
+ self,
1677
+ ail_graph,
1678
+ stage: OptimizationPassStage = OptimizationPassStage.AFTER_GLOBAL_SIMPLIFICATION,
1679
+ variable_kb=None,
1680
+ stack_items: dict[int, StackItem] | None = None,
1681
+ stack_pointer_tracker=None,
1682
+ **kwargs,
1683
+ ):
1684
+ addr_and_idx_to_blocks: dict[tuple[int, int | None], ailment.Block] = {}
1685
+ addr_to_blocks: dict[int, set[ailment.Block]] = defaultdict(set)
1686
+
1687
+ # update blocks_map to allow node_addr to node lookup
1688
+ def _updatedict_handler(node):
1689
+ addr_and_idx_to_blocks[(node.addr, node.idx)] = node
1690
+ addr_to_blocks[node.addr].add(node)
1691
+
1692
+ AILGraphWalker(ail_graph, _updatedict_handler).walk()
1693
+
1694
+ # Run each pass
1695
+ for pass_ in self._optimization_passes:
1696
+ if stage != pass_.STAGE:
1697
+ continue
1698
+
1699
+ if pass_ in DUPLICATING_OPTS + CONDENSING_OPTS and self.unoptimized_graph is None:
1700
+ # we should save a copy at the first time any optimization that could alter the structure
1701
+ # of the graph is applied
1702
+ self.unoptimized_graph = self._copy_graph(ail_graph)
1703
+
1704
+ pass_ = timethis(pass_)
1705
+ a = pass_(
1706
+ self.function,
1707
+ blocks_by_addr=addr_to_blocks,
1708
+ blocks_by_addr_and_idx=addr_and_idx_to_blocks,
1709
+ graph=ail_graph,
1710
+ variable_kb=variable_kb,
1711
+ vvar_id_start=self.vvar_id_start,
1712
+ entry_node_addr=self.entry_node_addr,
1713
+ scratch=self.optimization_scratch,
1714
+ force_loop_single_exit=self._force_loop_single_exit,
1715
+ refine_loops_with_single_successor=self._refine_loops_with_single_successor,
1716
+ complete_successors=self._complete_successors,
1717
+ stack_pointer_tracker=stack_pointer_tracker,
1718
+ notes=self.notes,
1719
+ static_vvars=self.static_vvars,
1720
+ static_buffers=self.static_buffers,
1721
+ **kwargs,
1722
+ )
1723
+ if a.out_graph:
1724
+ # use the new graph
1725
+ ail_graph = a.out_graph
1726
+ self.vvar_id_start = a.vvar_id_start
1727
+ if stack_items is not None and a.stack_items:
1728
+ stack_items.update(a.stack_items)
1729
+
1730
+ return ail_graph
1731
+
1732
+ @timethis
1733
+ def _create_function_argument_vvars(self, arg_list) -> dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]]:
1734
+ arg_vvars = {}
1735
+ for arg in arg_list:
1736
+ if isinstance(arg, SimRegisterVariable):
1737
+ # get the full register if needed
1738
+ arg_vvar = ailment.Expr.VirtualVariable(
1739
+ self._ail_manager.next_atom(),
1740
+ self.vvar_id_start,
1741
+ arg.bits,
1742
+ ailment.Expr.VirtualVariableCategory.PARAMETER,
1743
+ oident=(ailment.Expr.VirtualVariableCategory.REGISTER, arg.reg),
1744
+ ins_addr=self.function.addr,
1745
+ vex_block_addr=self.function.addr,
1746
+ )
1747
+ self.vvar_id_start += 1
1748
+ arg_vvars[arg_vvar.varid] = arg_vvar, arg
1749
+ elif isinstance(arg, SimStackVariable):
1750
+ arg_vvar = ailment.Expr.VirtualVariable(
1751
+ self._ail_manager.next_atom(),
1752
+ self.vvar_id_start,
1753
+ arg.bits,
1754
+ ailment.Expr.VirtualVariableCategory.PARAMETER,
1755
+ oident=(ailment.Expr.VirtualVariableCategory.STACK, arg.offset),
1756
+ ins_addr=self.function.addr,
1757
+ vex_block_addr=self.function.addr,
1758
+ )
1759
+ self.vvar_id_start += 1
1760
+ arg_vvars[arg_vvar.varid] = arg_vvar, arg
1761
+
1762
+ return arg_vvars
1763
+
1764
+ @timethis
1765
+ def _transform_to_ssa_level0(
1766
+ self, ail_graph: networkx.DiGraph, func_args: set[ailment.Expr.VirtualVariable]
1767
+ ) -> networkx.DiGraph:
1768
+ ssailification = self.project.analyses[Ssailification].prep(fail_fast=self._fail_fast)(
1769
+ self.function,
1770
+ ail_graph,
1771
+ entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
1772
+ ail_manager=self._ail_manager,
1773
+ ssa_stackvars=False,
1774
+ func_args=func_args,
1775
+ vvar_id_start=self.vvar_id_start,
1776
+ )
1777
+ self.vvar_id_start = ssailification.max_vvar_id + 1
1778
+ assert ssailification.out_graph is not None
1779
+ return ssailification.out_graph
1780
+
1781
+ @timethis
1782
+ def _transform_to_ssa_level1(
1783
+ self, ail_graph: networkx.DiGraph, func_args: set[ailment.Expr.VirtualVariable]
1784
+ ) -> networkx.DiGraph:
1785
+ ssailification = self.project.analyses.Ssailification(
1786
+ self.function,
1787
+ ail_graph,
1788
+ fail_fast=self._fail_fast,
1789
+ entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
1790
+ ail_manager=self._ail_manager,
1791
+ ssa_tmps=True,
1792
+ ssa_stackvars=True,
1793
+ func_args=func_args,
1794
+ vvar_id_start=self.vvar_id_start,
1795
+ )
1796
+ self.vvar_id_start = ssailification.max_vvar_id + 1
1797
+ self.secondary_stackvars = ssailification.secondary_stackvars
1798
+ return ssailification.out_graph
1799
+
1800
+ @timethis
1801
+ def _collect_dephi_vvar_mapping_and_rewrite_blocks(
1802
+ self, ail_graph: networkx.DiGraph, arg_vvars: dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]]
1803
+ ) -> tuple[dict[int, int], set[int]]:
1804
+ dephication = self.project.analyses.GraphDephicationVVarMapping(
1805
+ self.function,
1806
+ ail_graph,
1807
+ fail_fast=self._fail_fast,
1808
+ entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
1809
+ vvar_id_start=self.vvar_id_start,
1810
+ arg_vvars=[arg_vvar for arg_vvar, _ in arg_vvars.values()],
1811
+ )
1812
+ self.vvar_id_start = dephication.vvar_id_start + 1
1813
+ return dephication.vvar_to_vvar_mapping, dephication.copied_vvar_ids
1814
+
1815
+ @timethis
1816
+ def _make_argument_list(self) -> list[SimVariable]:
1817
+ if self.function.calling_convention is not None and self.function.prototype is not None:
1818
+ proto = (
1819
+ dereference_simtype_by_lib(self.function.prototype, self.function.prototype_libname)
1820
+ if self.function.prototype_libname
1821
+ else self.function.prototype
1822
+ )
1823
+ args: list[SimFunctionArgument] = self.function.calling_convention.arg_locs(proto)
1824
+ arg_vars: list[SimVariable] = []
1825
+ if args:
1826
+ arg_names = self.function.prototype.arg_names or [f"a{i}" for i in range(len(args))]
1827
+ for idx, arg in enumerate(args):
1828
+ if isinstance(arg, SimRegArg):
1829
+ argvar = SimRegisterVariable(
1830
+ self.project.arch.registers[arg.reg_name][0],
1831
+ arg.size,
1832
+ ident=f"arg_{idx}",
1833
+ name=arg_names[idx],
1834
+ region=self.function.addr,
1835
+ )
1836
+ elif isinstance(arg, SimStackArg):
1837
+ argvar = SimStackVariable(
1838
+ arg.stack_offset,
1839
+ arg.size,
1840
+ base="bp",
1841
+ ident=f"arg_{idx}",
1842
+ name=arg_names[idx],
1843
+ region=self.function.addr,
1844
+ )
1845
+ else:
1846
+ argvar = SimVariable(
1847
+ ident=f"arg_{idx}",
1848
+ name=arg_names[idx],
1849
+ region=self.function.addr,
1850
+ size=arg.size,
1851
+ )
1852
+ arg_vars.append(argvar)
1853
+ return arg_vars
1854
+ return []
1855
+
1856
+ @timethis
1857
+ def _make_callsites(
1858
+ self,
1859
+ ail_graph,
1860
+ func_args: set[ailment.Expr.VirtualVariable],
1861
+ stack_pointer_tracker=None,
1862
+ preserve_vvar_ids: set[int] | None = None,
1863
+ ):
1864
+ """
1865
+ Simplify all function call statements.
1866
+ """
1867
+
1868
+ # Computing reaching definitions
1869
+ rd = self.project.analyses.SReachingDefinitions(
1870
+ subject=self.function,
1871
+ func_graph=ail_graph,
1872
+ func_args=func_args,
1873
+ fail_fast=self._fail_fast,
1874
+ use_callee_saved_regs_at_return=not self._register_save_areas_removed,
1875
+ )
1876
+
1877
+ class TempClass: # pylint:disable=missing-class-docstring
1878
+ stack_arg_offsets = set()
1879
+ removed_vvar_ids = set()
1880
+
1881
+ def _handler(block):
1882
+ csm = self.project.analyses.AILCallSiteMaker(
1883
+ block,
1884
+ fail_fast=self._fail_fast,
1885
+ reaching_definitions=rd,
1886
+ stack_pointer_tracker=stack_pointer_tracker,
1887
+ ail_manager=self._ail_manager,
1888
+ )
1889
+ if csm.stack_arg_offsets is not None:
1890
+ TempClass.stack_arg_offsets |= csm.stack_arg_offsets
1891
+ if csm.removed_vvar_ids:
1892
+ TempClass.removed_vvar_ids |= csm.removed_vvar_ids
1893
+ if csm.result_block and csm.result_block != block:
1894
+ ail_block = csm.result_block
1895
+ simp = self.project.analyses.AILBlockSimplifier(
1896
+ ail_block,
1897
+ self.function.addr,
1898
+ fail_fast=self._fail_fast,
1899
+ stack_pointer_tracker=stack_pointer_tracker,
1900
+ peephole_optimizations=self.peephole_optimizations,
1901
+ preserve_vvar_ids=preserve_vvar_ids,
1902
+ )
1903
+ return simp.result_block
1904
+ return None
1905
+
1906
+ # rewriting call-sites at this point, pre-inlining, causes issues with incorrect call signatures
1907
+ if not self._inlining_parents:
1908
+ AILGraphWalker(ail_graph, _handler, replace_nodes=True).walk()
1909
+
1910
+ return ail_graph, TempClass.stack_arg_offsets, TempClass.removed_vvar_ids
1911
+
1912
+ @timethis
1913
+ def _make_returns(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
1914
+ """
1915
+ Work on each return statement and fill in its return expressions.
1916
+ """
1917
+ if self.function.calling_convention is None:
1918
+ # unknown calling convention. cannot do much about return expressions.
1919
+ return ail_graph
1920
+
1921
+ ReturnMaker(self._ail_manager, self.project.arch, self.function, ail_graph)
1922
+
1923
+ return ail_graph
1924
+
1925
+ @timethis
1926
+ def _make_function_prototype(self, arg_list: list[SimVariable], variable_kb):
1927
+ if self.function.prototype is not None:
1928
+ if not self.function.is_prototype_guessed:
1929
+ # do not overwrite an existing function prototype
1930
+ # if you want to re-generate the prototype, clear the existing one first
1931
+ return
1932
+ if isinstance(self.function.prototype.returnty, SimTypeFloat) or any(
1933
+ isinstance(arg, SimTypeFloat) for arg in self.function.prototype.args
1934
+ ):
1935
+ # Type inference does not yet support floating point variables, but calling convention analysis does
1936
+ # FIXME: remove this branch once type inference supports floating point variables
1937
+ return
1938
+
1939
+ variables = variable_kb.variables[self.function.addr]
1940
+ func_args = []
1941
+ for arg in arg_list:
1942
+ func_arg = None
1943
+ arg_ty = variables.get_variable_type(arg)
1944
+ if arg_ty is None:
1945
+ # determine type based on size
1946
+ if isinstance(arg, (SimRegisterVariable, SimStackVariable)):
1947
+ if arg.size == 1:
1948
+ func_arg = SimTypeChar()
1949
+ elif arg.size == 2:
1950
+ func_arg = SimTypeShort()
1951
+ elif arg.size == 4:
1952
+ func_arg = SimTypeInt()
1953
+ elif arg.size == 8:
1954
+ func_arg = SimTypeLongLong()
1955
+ else:
1956
+ l.warning("Unsupported argument size %d.", arg.size)
1957
+ else:
1958
+ func_arg = arg_ty
1959
+
1960
+ func_args.append(func_arg)
1961
+
1962
+ returnty = variables.get_variable_type(self.func_ret_var)
1963
+ if returnty is None or isinstance(returnty, SimTypeBottom):
1964
+ if self.function.prototype is not None and self.function.prototype.returnty is not None:
1965
+ returnty = self.function.prototype.returnty
1966
+ else:
1967
+ returnty = SimTypeInt()
1968
+
1969
+ self.function.prototype = SimTypeFunction(func_args, returnty).with_arch(self.project.arch)
1970
+ self.function.is_prototype_guessed = False
1971
+
1972
+ @timethis
1973
+ def _recover_and_link_variables(
1974
+ self,
1975
+ ail_graph,
1976
+ arg_list: list,
1977
+ arg_vvars: dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]],
1978
+ vvar2vvar: dict[int, int],
1979
+ type_hints: list[tuple[atoms.VirtualVariable | atoms.MemoryLocation, str]],
1980
+ ):
1981
+ # variable recovery
1982
+ tmp_kb = KnowledgeBase(self.project) if self.variable_kb is None else self.variable_kb
1983
+ tmp_kb.functions = self.kb.functions
1984
+ vr = self.project.analyses.VariableRecoveryFast(
1985
+ self.function, # pylint:disable=unused-variable
1986
+ fail_fast=self._fail_fast, # type:ignore
1987
+ func_graph=ail_graph,
1988
+ entry_node_addr=self.entry_node_addr,
1989
+ kb=tmp_kb, # type:ignore
1990
+ track_sp=False,
1991
+ func_args=arg_list,
1992
+ func_ret_var=self.func_ret_var,
1993
+ unify_variables=False,
1994
+ func_arg_vvars=arg_vvars,
1995
+ vvar_to_vvar=vvar2vvar,
1996
+ type_hints=type_hints,
1997
+ )
1998
+ # get ground-truth types
1999
+ var_manager = tmp_kb.variables[self.function.addr]
2000
+ groundtruth = {}
2001
+ for variable in var_manager.variables_with_manual_types:
2002
+ vartype = var_manager.variable_to_types.get(variable, None)
2003
+ if vartype is not None:
2004
+ for tv in vr.var_to_typevars[variable]:
2005
+ groundtruth[tv] = vartype
2006
+
2007
+ if self.function.prototype is not None and not self.function.is_prototype_guessed:
2008
+ for arg_i, (_, variable) in arg_vvars.items():
2009
+ if arg_i < len(self.function.prototype.args):
2010
+ for tv in vr.var_to_typevars[variable]:
2011
+ groundtruth[tv] = self.function.prototype.args[arg_i]
2012
+
2013
+ # get maximum sizes of each stack variable, regardless of its original type
2014
+ stackvar_max_sizes = var_manager.get_stackvar_max_sizes(self.stack_items)
2015
+ tv_max_sizes = {}
2016
+ for v, s in stackvar_max_sizes.items():
2017
+ assert isinstance(v, SimStackVariable)
2018
+ if v in vr.var_to_typevars:
2019
+ for tv in vr.var_to_typevars[v]:
2020
+ tv_max_sizes[tv] = s
2021
+ if v.offset in vr.stack_offset_typevars:
2022
+ tv = vr.stack_offset_typevars[v.offset]
2023
+ tv_max_sizes[tv] = s
2024
+ # TODO: Type inference for global variables
2025
+ # run type inference
2026
+ if self._must_struct:
2027
+ must_struct = set()
2028
+ for var, typevars in vr.var_to_typevars.items():
2029
+ if var.ident in self._must_struct:
2030
+ must_struct |= typevars
2031
+ else:
2032
+ must_struct = None
2033
+ total_type_constraints = sum(len(tc) for tc in vr.type_constraints.values()) if vr.type_constraints else 0
2034
+ if total_type_constraints > self._max_type_constraints:
2035
+ l.warning(
2036
+ "The number of type constraints (%d) is greater than the threshold (%d). Skipping type inference.",
2037
+ total_type_constraints,
2038
+ self._max_type_constraints,
2039
+ )
2040
+ else:
2041
+ try:
2042
+ tp = self.project.analyses[Typehoon].prep(
2043
+ kb=tmp_kb,
2044
+ fail_fast=self._fail_fast,
2045
+ )(
2046
+ vr.type_constraints,
2047
+ vr.func_typevar,
2048
+ var_mapping=vr.var_to_typevars,
2049
+ stack_offset_tvs=vr.stack_offset_typevars,
2050
+ must_struct=must_struct,
2051
+ ground_truth=groundtruth,
2052
+ stackvar_max_sizes=tv_max_sizes,
2053
+ constraint_set_degradation_threshold=self._type_constraint_set_degradation_threshold,
2054
+ )
2055
+ # tp.pp_constraints()
2056
+ # tp.pp_solution()
2057
+ tp.update_variable_types(
2058
+ self.function.addr,
2059
+ {
2060
+ v: t
2061
+ for v, t in vr.var_to_typevars.items()
2062
+ if isinstance(v, (SimRegisterVariable, SimStackVariable)) or v is self.func_ret_var
2063
+ },
2064
+ vr.stack_offset_typevars,
2065
+ )
2066
+ tp.update_variable_types(
2067
+ "global",
2068
+ {
2069
+ v: t
2070
+ for v, t in vr.var_to_typevars.items()
2071
+ if isinstance(v, SimMemoryVariable) and not isinstance(v, SimStackVariable)
2072
+ },
2073
+ )
2074
+ self.typehoon = tp
2075
+ except Exception: # pylint:disable=broad-except
2076
+ if self._fail_fast:
2077
+ raise
2078
+ l.warning(
2079
+ "Typehoon analysis failed. Variables will not have types. Please report to GitHub.", exc_info=True
2080
+ )
2081
+
2082
+ # for any left-over variables, assign Bottom type (which will get "corrected" into a default type in
2083
+ # VariableManager)
2084
+ bottype = SimTypeBottom().with_arch(self.project.arch)
2085
+ for var in var_manager._variables:
2086
+ if var not in var_manager.variable_to_types:
2087
+ var_manager.set_variable_type(var, bottype)
2088
+
2089
+ # Unify SSA variables
2090
+ tmp_kb.variables.global_manager.assign_variable_names(labels=self.kb.labels, types={SimMemoryVariable})
2091
+ liveness = self.project.analyses.SLiveness(
2092
+ self.function,
2093
+ func_graph=ail_graph,
2094
+ entry=next(iter(bb for bb in ail_graph if (bb.addr, bb.idx) == self.entry_node_addr)),
2095
+ arg_vvars=[vvar for vvar, _ in arg_vvars.values()],
2096
+ )
2097
+ var_manager.unify_variables(interference=liveness.interference_graph())
2098
+ var_manager.assign_unified_variable_names(
2099
+ labels=self.kb.labels,
2100
+ arg_names=list(self.function.prototype.arg_names) if self.function.prototype else None,
2101
+ reset=self._reset_variable_names,
2102
+ func_blocks=list(ail_graph),
2103
+ )
2104
+
2105
+ # Link variables and struct member information to every statement and expression
2106
+ for block in ail_graph.nodes():
2107
+ self._link_variables_on_block(block, tmp_kb)
2108
+
2109
+ if self._cache is not None:
2110
+ self._cache.arg_vvars = arg_vvars
2111
+ self._cache.type_constraints = vr.type_constraints
2112
+ self._cache.func_typevar = vr.func_typevar
2113
+ self._cache.var_to_typevar = vr.var_to_typevars
2114
+ self._cache.stack_offset_typevars = vr.stack_offset_typevars
2115
+ self._cache.stackvar_max_sizes = stackvar_max_sizes
2116
+
2117
+ return tmp_kb
2118
+
2119
+ def _link_variables_on_block(self, block, kb):
2120
+ """
2121
+ Link atoms (AIL expressions) in the given block to corresponding variables identified previously.
2122
+
2123
+ :param ailment.Block block: The AIL block to work on.
2124
+ :return: None
2125
+ """
2126
+
2127
+ variable_manager = kb.variables[self.function.addr]
2128
+ global_variables = kb.variables["global"]
2129
+
2130
+ for stmt_idx, stmt in enumerate(block.statements):
2131
+ stmt_type = type(stmt)
2132
+ if stmt_type is ailment.Stmt.Store:
2133
+ # find a memory variable
2134
+ mem_vars = variable_manager.find_variables_by_atom(block.addr, stmt_idx, stmt, block_idx=block.idx)
2135
+ if len(mem_vars) == 1:
2136
+ stmt.variable, stmt.offset = next(iter(mem_vars))
2137
+ else:
2138
+ # check if the dest address is a variable
2139
+ stmt: ailment.Stmt.Store
2140
+ # special handling for constant addresses
2141
+ if isinstance(stmt.addr, ailment.Expr.Const):
2142
+ # global variable?
2143
+ variables = global_variables.get_global_variables(stmt.addr.value)
2144
+ if variables:
2145
+ var = next(iter(variables))
2146
+ stmt.variable = var
2147
+ stmt.offset = 0
2148
+ else:
2149
+ self._link_variables_on_expr(
2150
+ variable_manager, global_variables, block, stmt_idx, stmt, stmt.addr
2151
+ )
2152
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.data)
2153
+
2154
+ # link struct member info
2155
+ if isinstance(stmt.variable, SimStackVariable):
2156
+ self._map_stackvar_to_struct_member(variable_manager, stmt, stmt.variable.offset)
2157
+
2158
+ elif stmt_type is ailment.Stmt.Assignment or stmt_type is ailment.Stmt.WeakAssignment:
2159
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.dst)
2160
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.src)
2161
+
2162
+ elif stmt_type is ailment.Stmt.CAS:
2163
+ for expr in [
2164
+ stmt.addr,
2165
+ stmt.data_lo,
2166
+ stmt.data_hi,
2167
+ stmt.expd_lo,
2168
+ stmt.expd_hi,
2169
+ stmt.old_lo,
2170
+ stmt.old_hi,
2171
+ ]:
2172
+ if expr is not None:
2173
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr)
2174
+
2175
+ elif stmt_type is ailment.Stmt.ConditionalJump:
2176
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.condition)
2177
+
2178
+ elif stmt_type is ailment.Stmt.Jump and not isinstance(stmt.target, ailment.Expr.Const):
2179
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.target)
2180
+
2181
+ elif stmt_type is ailment.Stmt.Call:
2182
+ self._link_variables_on_call(variable_manager, global_variables, block, stmt_idx, stmt, is_expr=False)
2183
+
2184
+ elif stmt_type is ailment.Stmt.Return:
2185
+ assert isinstance(stmt, ailment.Stmt.Return)
2186
+ self._link_variables_on_return(variable_manager, global_variables, block, stmt_idx, stmt)
2187
+
2188
+ def _link_variables_on_return(
2189
+ self, variable_manager, global_variables, block: ailment.Block, stmt_idx: int, stmt: ailment.Stmt.Return
2190
+ ):
2191
+ if stmt.ret_exprs:
2192
+ for ret_expr in stmt.ret_exprs:
2193
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, ret_expr)
2194
+
2195
+ def _link_variables_on_call(self, variable_manager, global_variables, block, stmt_idx, stmt, is_expr=False):
2196
+ if not isinstance(stmt.target, ailment.Expr.Const):
2197
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.target)
2198
+ if stmt.args:
2199
+ for arg in stmt.args:
2200
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, arg)
2201
+ if not is_expr and stmt.ret_expr:
2202
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.ret_expr)
2203
+
2204
+ def _link_variables_on_expr(self, variable_manager, global_variables, block, stmt_idx, stmt, expr):
2205
+ """
2206
+ Link atoms (AIL expressions) in the given expression to corresponding variables identified previously.
2207
+
2208
+ :param variable_manager: Variable manager of the function.
2209
+ :param ailment.Block block: AIL block.
2210
+ :param int stmt_idx: ID of the statement.
2211
+ :param stmt: The AIL statement that `expr` belongs to.
2212
+ :param expr: The AIl expression to work on.
2213
+ :return: None
2214
+ """
2215
+
2216
+ if type(expr) is ailment.Expr.Register:
2217
+ # find a register variable
2218
+ reg_vars = variable_manager.find_variables_by_atom(block.addr, stmt_idx, expr, block_idx=block.idx)
2219
+ final_reg_vars = set()
2220
+ if len(reg_vars) > 1:
2221
+ # take phi variables
2222
+ for reg_var in reg_vars:
2223
+ if variable_manager.is_phi_variable(reg_var[0]):
2224
+ final_reg_vars.add(reg_var)
2225
+ else:
2226
+ final_reg_vars = reg_vars
2227
+ if len(final_reg_vars) >= 1:
2228
+ reg_var, offset = next(iter(final_reg_vars))
2229
+ expr.variable = reg_var
2230
+ expr.variable_offset = offset
2231
+
2232
+ elif type(expr) is ailment.Expr.VirtualVariable:
2233
+ vars_ = variable_manager.find_variables_by_atom(block.addr, stmt_idx, expr, block_idx=block.idx)
2234
+ if len(vars_) >= 1:
2235
+ var, offset = next(iter(vars_))
2236
+ expr.variable = var
2237
+ expr.variable_offset = offset
2238
+
2239
+ if isinstance(expr, ailment.Expr.VirtualVariable) and expr.was_stack:
2240
+ self._map_stackvar_to_struct_member(variable_manager, expr, expr.stack_offset)
2241
+
2242
+ elif type(expr) is ailment.Expr.Load:
2243
+ variables = variable_manager.find_variables_by_atom(block.addr, stmt_idx, expr, block_idx=block.idx)
2244
+ if len(variables) == 0:
2245
+ # if it's a constant addr, maybe it's referencing an extern location
2246
+ base_addr, offset = self.parse_variable_addr(expr.addr)
2247
+ if offset is not None and isinstance(offset, ailment.Expr.Expression):
2248
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, offset)
2249
+ if base_addr is not None:
2250
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, base_addr)
2251
+
2252
+ # if we are accessing the variable directly (offset == 0), we link the variable onto this expression
2253
+ if (
2254
+ offset == 0 or (isinstance(offset, ailment.Expr.Const) and offset.value == 0)
2255
+ ) and "reference_variable" in base_addr.tags:
2256
+ expr.variable = base_addr.tags["reference_variable"]
2257
+ expr.variable_offset = base_addr.tags["reference_variable_offset"]
2258
+
2259
+ if base_addr is None and offset is None:
2260
+ # this is a local variable
2261
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.addr)
2262
+ if "reference_variable" in expr.addr.tags and expr.addr.tags["reference_variable"] is not None:
2263
+ # copy over the variable to this expr since the variable on a constant is supposed to be a
2264
+ # reference variable.
2265
+ expr.variable = expr.addr.tags["reference_variable"]
2266
+ expr.variable_offset = expr.addr.tags["reference_variable_offset"]
2267
+ else:
2268
+ if len(variables) > 1:
2269
+ l.error(
2270
+ "More than one variable are available for atom %s. Consider fixing it using phi nodes.", expr
2271
+ )
2272
+ var, offset = next(iter(variables))
2273
+ expr.variable = var
2274
+ expr.variable_offset = offset
2275
+
2276
+ if isinstance(var, SimStackVariable):
2277
+ self._map_stackvar_to_struct_member(variable_manager, expr, var.offset)
2278
+
2279
+ elif type(expr) is ailment.Expr.BinaryOp:
2280
+ variables = variable_manager.find_variables_by_atom(block.addr, stmt_idx, expr, block_idx=block.idx)
2281
+ if len(variables) >= 1:
2282
+ var, offset = next(iter(variables))
2283
+ expr.variable = var
2284
+ expr.variable_offset = offset
2285
+ else:
2286
+ self._link_variables_on_expr(
2287
+ variable_manager, global_variables, block, stmt_idx, stmt, expr.operands[0]
2288
+ )
2289
+ self._link_variables_on_expr(
2290
+ variable_manager, global_variables, block, stmt_idx, stmt, expr.operands[1]
2291
+ )
2292
+
2293
+ elif type(expr) is ailment.Expr.UnaryOp:
2294
+ variables = variable_manager.find_variables_by_atom(block.addr, stmt_idx, expr, block_idx=block.idx)
2295
+ if len(variables) >= 1:
2296
+ var, offset = next(iter(variables))
2297
+ expr.variable = var
2298
+ expr.variable_offset = offset
2299
+ else:
2300
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.operand)
2301
+
2302
+ elif type(expr) in {ailment.Expr.Convert, ailment.Expr.Reinterpret}:
2303
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.operand)
2304
+
2305
+ elif type(expr) is ailment.Expr.ITE:
2306
+ variables = variable_manager.find_variables_by_atom(block.addr, stmt_idx, expr, block_idx=block.idx)
2307
+ if len(variables) >= 1:
2308
+ var, offset = next(iter(variables))
2309
+ expr.variable = var
2310
+ expr.variable_offset = offset
2311
+ else:
2312
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.cond)
2313
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.iftrue)
2314
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.iffalse)
2315
+
2316
+ elif isinstance(expr, ailment.Expr.BasePointerOffset):
2317
+ variables = variable_manager.find_variables_by_atom(block.addr, stmt_idx, expr, block_idx=block.idx)
2318
+ if len(variables) >= 1:
2319
+ var, offset = next(iter(variables))
2320
+ expr.variable = var
2321
+ expr.variable_offset = offset
2322
+
2323
+ elif isinstance(expr, ailment.Expr.Const) and expr.is_int:
2324
+ # custom string?
2325
+ if expr.tags.get("custom_string", False):
2326
+ s = self.kb.custom_strings[expr.value]
2327
+ ty = (
2328
+ expr.tags["type"]
2329
+ if "type" in expr.tags
2330
+ else SimTypePointer(SimTypeChar()).with_arch(self.project.arch)
2331
+ )
2332
+ expr.tags["reference_values"] = {
2333
+ ty: s,
2334
+ }
2335
+ else:
2336
+ # global variable?
2337
+ global_vars = global_variables.get_global_variables(expr.value_int)
2338
+ # detect if there is a related symbol
2339
+ if not global_vars and self.project.loader.find_object_containing(expr.value_int):
2340
+ symbol = self.project.loader.find_symbol(expr.value)
2341
+ if symbol is not None:
2342
+ # Create a new global variable if there isn't one already
2343
+ global_vars = global_variables.get_global_variables(symbol.rebased_addr)
2344
+ if not global_vars:
2345
+ global_var = SimMemoryVariable(symbol.rebased_addr, symbol.size, name=symbol.name)
2346
+ global_variables.add_variable("global", global_var.addr, global_var)
2347
+ global_vars = {global_var}
2348
+ if global_vars:
2349
+ global_var = next(iter(global_vars))
2350
+ expr.tags["reference_variable"] = global_var
2351
+ expr.tags["reference_variable_offset"] = 0
2352
+
2353
+ elif isinstance(expr, ailment.Stmt.Call):
2354
+ self._link_variables_on_call(variable_manager, global_variables, block, stmt_idx, expr, is_expr=True)
2355
+
2356
+ elif isinstance(expr, ailment.Expr.VEXCCallExpression):
2357
+ for operand in expr.operands:
2358
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, operand)
2359
+
2360
+ elif isinstance(expr, ailment.Expr.DirtyExpression):
2361
+ for operand in expr.operands:
2362
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, operand)
2363
+ if expr.maddr:
2364
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.maddr)
2365
+ if expr.guard:
2366
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, expr.guard)
2367
+
2368
+ elif isinstance(expr, ailment.Expr.Phi):
2369
+ for _, vvar in expr.src_and_vvars:
2370
+ if vvar is not None:
2371
+ self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, vvar)
2372
+
2373
+ def _map_stackvar_to_struct_member(
2374
+ self,
2375
+ variable_manager,
2376
+ expr_or_stmt: ailment.expression.Expression | ailment.statement.Statement,
2377
+ the_stack_offset: int,
2378
+ ) -> bool:
2379
+ any_struct_found = False
2380
+ off = the_stack_offset
2381
+ for stack_off in variable_manager.stack_offset_to_struct.irange(maximum=off, reverse=True):
2382
+ the_var, vartype = variable_manager.stack_offset_to_struct[stack_off]
2383
+ if stack_off <= off < stack_off + vartype.size // self.project.arch.byte_width:
2384
+ expr_or_stmt.tags["struct_member_info"] = off - stack_off, the_var, vartype
2385
+ any_struct_found = True
2386
+ break
2387
+ if stack_off + vartype.size // self.project.arch.byte_width <= off:
2388
+ break
2389
+ return any_struct_found
2390
+
2391
+ def _function_graph_to_ail_graph(self, func_graph, blocks_by_addr_and_size=None):
2392
+ if blocks_by_addr_and_size is None:
2393
+ blocks_by_addr_and_size = self._blocks_by_addr_and_size
2394
+ assert blocks_by_addr_and_size is not None
2395
+
2396
+ graph = networkx.DiGraph()
2397
+
2398
+ entry_node = next(iter(node for node in func_graph if node.addr == self.entry_node_addr[0]), None)
2399
+ if entry_node is None:
2400
+ raise AngrDecompilationError(
2401
+ f"Entry node with address {self.entry_node_addr[0]:#x} not found in the function graph"
2402
+ )
2403
+
2404
+ # add the entry node into the graph
2405
+ ail_block = blocks_by_addr_and_size.get((entry_node.addr, entry_node.size))
2406
+ if ail_block is None:
2407
+ raise AngrDecompilationError(f"AIL block at address {entry_node.addr:#x} not found")
2408
+ graph.add_node(ail_block)
2409
+
2410
+ # get all descendants and only include them in the AIL graph.
2411
+ # this way all unreachable blocks will be excluded from the AIL graph.
2412
+ descendants = networkx.descendants(func_graph, entry_node) | {entry_node}
2413
+ for src_node, dst_node, data in networkx.subgraph_view(
2414
+ func_graph, filter_node=lambda n: n in descendants
2415
+ ).edges(data=True):
2416
+ src = blocks_by_addr_and_size.get((src_node.addr, src_node.size))
2417
+ dst = blocks_by_addr_and_size.get((dst_node.addr, dst_node.size))
2418
+
2419
+ if src is not None and dst is not None:
2420
+ graph.add_edge(src, dst, **data)
2421
+
2422
+ return graph
2423
+
2424
+ @staticmethod
2425
+ def _duplicate_orphaned_cond_jumps(ail_graph) -> networkx.DiGraph:
2426
+ """
2427
+ Find conditional jumps that are orphaned (e.g., being the only instruction of the block). If these blocks have
2428
+ multiple predecessors, duplicate them to all predecessors. This is a workaround for cases where these
2429
+ conditional jumps rely on comparisons in more than one predecessor and we cannot resolve ccalls into
2430
+ comparisons.
2431
+
2432
+ This pass runs before any SSA transformations.
2433
+
2434
+ # 140017162 jz short 1400171e1
2435
+ """
2436
+
2437
+ for block in list(ail_graph):
2438
+ if (
2439
+ len(block.statements) > 1
2440
+ and block.statements[0].tags["ins_addr"] == block.statements[-1].tags["ins_addr"]
2441
+ ):
2442
+ preds = list(ail_graph.predecessors(block))
2443
+ if len(preds) > 1 and block not in preds:
2444
+ has_ccall = any(
2445
+ isinstance(stmt, ailment.Stmt.Assignment)
2446
+ and isinstance(stmt.src, ailment.Expr.VEXCCallExpression)
2447
+ for stmt in block.statements
2448
+ )
2449
+ if has_ccall:
2450
+ # duplicate this block to its predecessors!
2451
+ preds = sorted(preds, key=lambda x: x.addr)
2452
+ succs = sorted(ail_graph.successors(block), key=lambda x: x.addr)
2453
+ # FIXME: We should track block IDs globally and ensure block IDs do not collide
2454
+ block_idx_start = block.idx + 1 if block.idx is not None else 1
2455
+ for pred in preds[1:]:
2456
+ ail_graph.remove_edge(pred, block)
2457
+ new_block = block.copy()
2458
+ new_block.idx = block_idx_start
2459
+ block_idx_start += 1
2460
+ ail_graph.add_edge(pred, new_block)
2461
+ for succ in succs:
2462
+ ail_graph.add_edge(new_block, succ if succ is not block else new_block)
2463
+
2464
+ return ail_graph
2465
+
2466
+ def _rewrite_jump_rax_calls(self, ail_graph: networkx.DiGraph) -> networkx.DiGraph:
2467
+ """
2468
+ Rewrite calls to special functions (e.g., guard_dispatch_icall_nop) into `call rax`.
2469
+ """
2470
+
2471
+ if self.project.arch.name != "AMD64":
2472
+ return ail_graph
2473
+ if self._cfg is None:
2474
+ return ail_graph
2475
+
2476
+ for block in ail_graph:
2477
+ if not block.statements:
2478
+ continue
2479
+ assert block.addr is not None
2480
+ last_stmt = block.statements[-1]
2481
+ if isinstance(last_stmt, ailment.Stmt.Call):
2482
+ # we can't examine the call target at this point because constant propagation hasn't run yet; we consult
2483
+ # the CFG instead
2484
+ callsite_node = self._cfg.get_any_node(block.addr, anyaddr=True)
2485
+ if callsite_node is None:
2486
+ break
2487
+ callees = self._cfg.get_successors(callsite_node, jumpkind="Ijk_Call")
2488
+ if len(callees) != 1:
2489
+ break
2490
+ callee = callees[0].addr
2491
+ if self.kb.functions.contains_addr(callee):
2492
+ callee_func = self.kb.functions.get_by_addr(callee)
2493
+ if callee_func.info.get("jmp_rax", False) is True:
2494
+ # rewrite this statement into Call(rax)
2495
+ call_stmt = last_stmt.copy()
2496
+ call_stmt.target = ailment.Expr.Register(
2497
+ self._ail_manager.next_atom(),
2498
+ None,
2499
+ self.project.arch.registers["rax"][0],
2500
+ 64,
2501
+ ins_addr=call_stmt.tags["ins_addr"],
2502
+ )
2503
+ block.statements[-1] = call_stmt
2504
+
2505
+ return ail_graph
2506
+
2507
+ def _rewrite_ite_expressions(self, ail_graph):
2508
+ cfg = self._cfg
2509
+ for block in list(ail_graph):
2510
+ if cfg is not None and block.addr in cfg.jump_tables:
2511
+ continue
2512
+
2513
+ ite_ins_addrs = []
2514
+ cas_ins_addrs = set()
2515
+ for stmt in block.statements:
2516
+ if isinstance(stmt, ailment.Stmt.CAS):
2517
+ # we do not rewrite ITE statements that are caused by CAS statements
2518
+ cas_ins_addrs.add(stmt.tags["ins_addr"])
2519
+ elif (
2520
+ isinstance(stmt, ailment.Stmt.Assignment)
2521
+ and isinstance(stmt.src, ailment.Expr.ITE)
2522
+ and stmt.tags["ins_addr"] not in ite_ins_addrs
2523
+ and stmt.tags["ins_addr"] not in cas_ins_addrs
2524
+ ):
2525
+ ite_ins_addrs.append(stmt.tags["ins_addr"])
2526
+
2527
+ if ite_ins_addrs:
2528
+ block_addr = block.addr
2529
+ for ite_ins_addr in ite_ins_addrs:
2530
+ block_addr = self._create_triangle_for_ite_expression(ail_graph, block_addr, ite_ins_addr)
2531
+ if block_addr is None or block_addr >= block.addr + block.original_size:
2532
+ break
2533
+
2534
+ def _create_triangle_for_ite_expression(self, ail_graph, block_addr: int, ite_ins_addr: int):
2535
+ ite_insn_only_block = self.project.factory.block(ite_ins_addr, num_inst=1)
2536
+ ite_insn_size = ite_insn_only_block.size
2537
+ assert ite_insn_size is not None
2538
+ if ite_insn_size <= 2: # we need an address for true_block and another address for false_block
2539
+ return None
2540
+ if ite_insn_only_block.vex.exit_statements:
2541
+ return None
2542
+
2543
+ # relift the head and the ITE instruction
2544
+ new_head = self.project.factory.block(
2545
+ block_addr, size=ite_ins_addr - block_addr + ite_insn_size, cross_insn_opt=False
2546
+ )
2547
+ new_head_ail = ailment.IRSBConverter.convert(new_head.vex, self._ail_manager)
2548
+ # remove all statements between the ITE expression and the very end of the block
2549
+ ite_expr_stmt_idx = None
2550
+ ite_expr_stmt = None
2551
+ for idx, stmt in enumerate(new_head_ail.statements):
2552
+ if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.ITE):
2553
+ ite_expr_stmt_idx = idx
2554
+ ite_expr_stmt = stmt
2555
+ break
2556
+ if ite_expr_stmt_idx is None:
2557
+ return None
2558
+ assert ite_expr_stmt is not None
2559
+
2560
+ ite_expr: ailment.Expr.ITE = ite_expr_stmt.src # type: ignore
2561
+ new_head_ail.statements = new_head_ail.statements[:ite_expr_stmt_idx]
2562
+ # build the conditional jump
2563
+ true_block_addr = ite_ins_addr + 1
2564
+ false_block_addr = ite_ins_addr + 2
2565
+ cond_jump_stmt = ailment.Stmt.ConditionalJump(
2566
+ ite_expr_stmt.idx,
2567
+ ite_expr.cond,
2568
+ ailment.Expr.Const(None, None, true_block_addr, self.project.arch.bits, **ite_expr_stmt.tags),
2569
+ ailment.Expr.Const(None, None, false_block_addr, self.project.arch.bits, **ite_expr_stmt.tags),
2570
+ **ite_expr_stmt.tags,
2571
+ )
2572
+ new_head_ail.statements.append(cond_jump_stmt)
2573
+
2574
+ # build the true block
2575
+ true_block = self.project.factory.block(ite_ins_addr, num_inst=1)
2576
+ true_block_ail = ailment.IRSBConverter.convert(true_block.vex, self._ail_manager)
2577
+ true_block_ail.addr = true_block_addr
2578
+
2579
+ ite_expr_stmt_idx = None
2580
+ ite_expr_stmt = None
2581
+ for idx, stmt in enumerate(true_block_ail.statements):
2582
+ if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.ITE):
2583
+ ite_expr_stmt_idx = idx
2584
+ ite_expr_stmt = stmt
2585
+ break
2586
+ if ite_expr_stmt_idx is None:
2587
+ return None
2588
+ assert ite_expr_stmt is not None
2589
+
2590
+ true_block_ail.statements[ite_expr_stmt_idx] = ailment.Stmt.Assignment(
2591
+ ite_expr_stmt.idx, ite_expr_stmt.dst, ite_expr_stmt.src.iftrue, **ite_expr_stmt.tags
2592
+ )
2593
+
2594
+ # build the false block
2595
+ false_block = self.project.factory.block(ite_ins_addr, num_inst=1)
2596
+ false_block_ail = ailment.IRSBConverter.convert(false_block.vex, self._ail_manager)
2597
+ false_block_ail.addr = false_block_addr
2598
+
2599
+ ite_expr_stmt_idx = None
2600
+ ite_expr_stmt = None
2601
+ for idx, stmt in enumerate(false_block_ail.statements):
2602
+ if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.ITE):
2603
+ ite_expr_stmt_idx = idx
2604
+ ite_expr_stmt = stmt
2605
+ break
2606
+ if ite_expr_stmt_idx is None:
2607
+ return None
2608
+ assert ite_expr_stmt is not None
2609
+
2610
+ false_block_ail.statements[ite_expr_stmt_idx] = ailment.Stmt.Assignment(
2611
+ ite_expr_stmt.idx, ite_expr_stmt.dst, ite_expr_stmt.src.iffalse, **ite_expr_stmt.tags
2612
+ )
2613
+
2614
+ original_block = next(iter(b for b in ail_graph if b.addr == block_addr))
2615
+
2616
+ original_block_in_edges = list(ail_graph.in_edges(original_block, data=True))
2617
+ original_block_out_edges = list(ail_graph.out_edges(original_block, data=True))
2618
+
2619
+ # build the target block if the target block does not exist in the current function
2620
+ end_block_addr = ite_ins_addr + ite_insn_size
2621
+ if block_addr < end_block_addr < block_addr + original_block.original_size:
2622
+ end_block = self.project.factory.block(
2623
+ ite_ins_addr + ite_insn_size,
2624
+ size=block_addr + original_block.original_size - (ite_ins_addr + ite_insn_size),
2625
+ cross_insn_opt=False,
2626
+ )
2627
+ end_block_ail = ailment.IRSBConverter.convert(end_block.vex, self._ail_manager)
2628
+ else:
2629
+ try:
2630
+ end_block_ail = next(iter(b for b in ail_graph if b.addr == end_block_addr))
2631
+ except StopIteration:
2632
+ return None
2633
+
2634
+ # last check: if the first instruction of the end block has Sar, then we bail (due to the peephole optimization
2635
+ # SarToSignedDiv)
2636
+ for stmt in end_block_ail.statements:
2637
+ if stmt.tags["ins_addr"] > end_block_ail.addr:
2638
+ break
2639
+ if ( # pylint:disable=no-member
2640
+ isinstance(stmt, ailment.Stmt.Assignment)
2641
+ and isinstance(stmt.src, ailment.Expr.BinaryOp)
2642
+ and stmt.src.op == "Sar"
2643
+ ):
2644
+ return None
2645
+
2646
+ # corner-case: the last statement of original_block might have been patched by _remove_redundant_jump_blocks.
2647
+ # we detect such case and fix it in new_head_ail
2648
+ self._remove_redundant_jump_blocks_repatch_relifted_block(original_block, end_block_ail)
2649
+
2650
+ ail_graph.remove_node(original_block)
2651
+
2652
+ if end_block_ail not in ail_graph:
2653
+ # newly created. add it and the necessary edges into the graph
2654
+ for _, dst, data in original_block_out_edges:
2655
+ if dst is original_block:
2656
+ ail_graph.add_edge(end_block_ail, new_head_ail, **data)
2657
+ else:
2658
+ ail_graph.add_edge(end_block_ail, dst, **data)
2659
+
2660
+ # in edges
2661
+ for src, _, data in original_block_in_edges:
2662
+ if src is original_block:
2663
+ # loop
2664
+ ail_graph.add_edge(end_block_ail, new_head_ail, **data)
2665
+ else:
2666
+ ail_graph.add_edge(src, new_head_ail, **data)
2667
+
2668
+ # triangle
2669
+ ail_graph.add_edge(new_head_ail, true_block_ail)
2670
+ ail_graph.add_edge(new_head_ail, false_block_ail)
2671
+ ail_graph.add_edge(true_block_ail, end_block_ail)
2672
+ ail_graph.add_edge(false_block_ail, end_block_ail)
2673
+
2674
+ return end_block_ail.addr
2675
+
2676
+ def _fix_abnormal_switch_case_heads(self, ail_graph: networkx.DiGraph) -> None:
2677
+ """
2678
+ Detect the existence of switch-case heads whose indirect jump node has more than one predecessor, and attempt
2679
+ to fix those cases by altering the graph.
2680
+ """
2681
+
2682
+ if self._cfg is None:
2683
+ return
2684
+
2685
+ if not self._cfg.jump_tables:
2686
+ return
2687
+
2688
+ node_dict: defaultdict[int, list[ailment.Block]] = defaultdict(list)
2689
+ for node in ail_graph:
2690
+ node_dict[node.addr].append(node)
2691
+
2692
+ candidates = []
2693
+ for block_addr in self._cfg.jump_tables:
2694
+ block_nodes = node_dict[block_addr]
2695
+ for block_node in block_nodes:
2696
+ if ail_graph.in_degree[block_node] > 1:
2697
+ # found it
2698
+ candidates.append(block_node)
2699
+
2700
+ if not candidates:
2701
+ return
2702
+
2703
+ sorted_nodes = GraphUtils.quasi_topological_sort_nodes(ail_graph)
2704
+ node_to_rank = {node: rank for rank, node in enumerate(sorted_nodes)}
2705
+ for candidate in candidates:
2706
+ # determine the "intended" switch-case head using topological order
2707
+ preds = list(ail_graph.predecessors(candidate))
2708
+ preds = sorted(preds, key=lambda n_: node_to_rank[n_])
2709
+ intended_head = preds[0]
2710
+ other_heads = preds[1:]
2711
+
2712
+ # I've seen cases where there is one more block between the actual intended head and the candidate.
2713
+ # binary 7995a0325b446c462bdb6ae10b692eee2ecadd8e888e9d7729befe4412007afb, block 0x140032760
2714
+ while ail_graph.out_degree[intended_head] == 1 and ail_graph.in_degree[intended_head] == 1:
2715
+ intended_head = next(iter(ail_graph.predecessors(intended_head)))
2716
+
2717
+ # now here is the tricky part. there are two cases:
2718
+ # Case 1: the intended head and the other heads share the same suffix (of instructions)
2719
+ # Example:
2720
+ # ; binary 736cb27201273f6c4f83da362c9595b50d12333362e02bc7a77dd327cc6b045a
2721
+ # 0041DA97 mov ecx, [esp+2Ch+var_18] ; this is the intended head
2722
+ # 0041DA9B mov ecx, [ecx]
2723
+ # 0041DA9D cmp ecx, 9
2724
+ # 0041DAA0 jbe loc_41D5A8
2725
+ #
2726
+ # 0041D599 mov ecx, [ecx] ; this is the other head
2727
+ # 0041D59B mov [esp+2Ch+var_10], eax
2728
+ # 0041D59F cmp ecx, 9
2729
+ # 0041D5A2 ja loc_41DAA6 ; fallthrough to 0x41d5a8
2730
+ # given the overlap of two instructions at the end of both blocks, we will alter the second block to remove
2731
+ # the overlapped instructions and add an unconditional jump so that it jumps to 0x41da9d.
2732
+ # this is the most common case created by jump threading optimization in compilers. it's easy to handle.
2733
+
2734
+ # Case 2 & 3: the intended head and the other heads do not share the same suffix of instructions. in this
2735
+ # case, we have two choices:
2736
+ # Case 2: The intended head has two successors, but at least one unintended head has only one successor.
2737
+ # we cannot reliably convert the blocks into a properly structured switch-case construct. we will
2738
+ # last instruction of all other heads to jump to the cmp instruction in the intended head, but do
2739
+ # not remove any other instructions in these other heads. this is unsound, but is the best we can
2740
+ # do in this case.
2741
+ # Case 3: The intended head has only one successor (which is the indirect jump node). during structuring,
2742
+ # we expect it will be structured as a no-default-node switch-case construct. in this case, we
2743
+ # can simply remove the edges from all other heads to the jump node and only leave the edge from
2744
+ # the intended head to the jump node. we will see goto statements in the output, but this will
2745
+ # lead to correct structuring result.
2746
+
2747
+ overlaps = [self._get_overlapping_suffix_instructions(intended_head, head) for head in other_heads]
2748
+ if overlaps and (overlap := min(overlaps)) > 0:
2749
+ # Case 1
2750
+ self._fix_abnormal_switch_case_heads_case1(ail_graph, candidate, intended_head, other_heads, overlap)
2751
+ elif ail_graph.out_degree[intended_head] == 2:
2752
+ # Case 2
2753
+ l.warning("Switch-case at %#x has multiple head nodes but cannot be fixed soundly.", candidate.addr)
2754
+ # find the comparison instruction in the intended head
2755
+ comparison_stmt = None
2756
+ if "cc_op" in self.project.arch.registers:
2757
+ comparison_stmt = next(
2758
+ iter(
2759
+ stmt
2760
+ for stmt in intended_head.statements
2761
+ if isinstance(stmt, ailment.Stmt.Assignment)
2762
+ and isinstance(stmt.dst, ailment.Expr.Register)
2763
+ and stmt.dst.reg_offset == self.project.arch.registers["cc_op"][0]
2764
+ ),
2765
+ None,
2766
+ )
2767
+ intended_head_block = self.project.factory.block(intended_head.addr, size=intended_head.original_size)
2768
+ if comparison_stmt is not None:
2769
+ cmp_rpos = len(intended_head_block.instruction_addrs) - intended_head_block.instruction_addrs.index(
2770
+ comparison_stmt.tags["ins_addr"]
2771
+ )
2772
+ else:
2773
+ cmp_rpos = min(len(intended_head_block.instruction_addrs), 2)
2774
+ self._fix_abnormal_switch_case_heads_case2(
2775
+ ail_graph,
2776
+ candidate,
2777
+ intended_head,
2778
+ other_heads,
2779
+ intended_head_split_insns=cmp_rpos,
2780
+ other_head_split_insns=0,
2781
+ )
2782
+ else:
2783
+ # Case 3
2784
+ self._fix_abnormal_switch_case_heads_case3(
2785
+ candidate,
2786
+ other_heads,
2787
+ )
2788
+
2789
+ def _get_overlapping_suffix_instructions(self, ailblock_0: ailment.Block, ailblock_1: ailment.Block) -> int:
2790
+ # we first compare their ending conditional jumps
2791
+ if not self._get_overlapping_suffix_instructions_compare_conditional_jumps(ailblock_0, ailblock_1):
2792
+ return 0
2793
+
2794
+ # we re-lift the blocks and compare the instructions
2795
+ block_0 = self.project.factory.block(ailblock_0.addr, size=ailblock_0.original_size)
2796
+ block_1 = self.project.factory.block(ailblock_1.addr, size=ailblock_1.original_size)
2797
+
2798
+ i0 = len(block_0.capstone.insns) - 2
2799
+ i1 = len(block_1.capstone.insns) - 2
2800
+ overlap = 1
2801
+ while i0 >= 0 and i1 >= 0:
2802
+ same = self._get_overlapping_suffix_instructions_compare_instructions(
2803
+ block_0.capstone.insns[i0], block_1.capstone.insns[i1]
2804
+ )
2805
+ if not same:
2806
+ break
2807
+ overlap += 1
2808
+ i0 -= 1
2809
+ i1 -= 1
2810
+
2811
+ return overlap
2812
+
2813
+ @staticmethod
2814
+ def _get_overlapping_suffix_instructions_compare_instructions(insn_0, insn_1) -> bool:
2815
+ return insn_0.mnemonic == insn_1.mnemonic and insn_0.op_str == insn_1.op_str
2816
+
2817
+ @staticmethod
2818
+ def _get_overlapping_suffix_instructions_compare_conditional_jumps(
2819
+ ailblock_0: ailment.Block, ailblock_1: ailment.Block
2820
+ ) -> bool:
2821
+ if len(ailblock_0.statements) == 0 or len(ailblock_1.statements) == 0:
2822
+ return False
2823
+
2824
+ # 12 | 0x41d5a2 | t17 = (t4 <= 0x9<32>)
2825
+ # 13 | 0x41d5a2 | t16 = Conv(1->32, t17)
2826
+ # 14 | 0x41d5a2 | t14 = t16
2827
+ # 15 | 0x41d5a2 | t18 = Conv(32->1, t14)
2828
+ # 16 | 0x41d5a2 | t9 = t18
2829
+ # 17 | 0x41d5a2 | if (t9) { Goto 0x41d5a8<32> } else { Goto 0x41daa6<32> }
2830
+
2831
+ last_stmt_0 = ailblock_0.statements[-1]
2832
+ last_stmt_1 = ailblock_1.statements[-1]
2833
+ if not (
2834
+ isinstance(last_stmt_0, ailment.Stmt.ConditionalJump)
2835
+ and isinstance(last_stmt_1, ailment.Stmt.ConditionalJump)
2836
+ ):
2837
+ return False
2838
+
2839
+ last_cmp_stmt_0 = next(
2840
+ iter(
2841
+ stmt
2842
+ for stmt in reversed(ailblock_0.statements)
2843
+ if isinstance(stmt, ailment.Stmt.Assignment)
2844
+ and isinstance(stmt.src, ailment.Expr.BinaryOp)
2845
+ and stmt.src.op in ailment.Expr.BinaryOp.COMPARISON_NEGATION
2846
+ and stmt.tags["ins_addr"] == last_stmt_0.tags["ins_addr"]
2847
+ ),
2848
+ None,
2849
+ )
2850
+ last_cmp_stmt_1 = next(
2851
+ iter(
2852
+ stmt
2853
+ for stmt in reversed(ailblock_1.statements)
2854
+ if isinstance(stmt, ailment.Stmt.Assignment)
2855
+ and isinstance(stmt.src, ailment.Expr.BinaryOp)
2856
+ and stmt.src.op in ailment.Expr.BinaryOp.COMPARISON_NEGATION
2857
+ and stmt.tags["ins_addr"] == last_stmt_1.tags["ins_addr"]
2858
+ ),
2859
+ None,
2860
+ )
2861
+ return (
2862
+ last_cmp_stmt_0 is not None
2863
+ and last_cmp_stmt_1 is not None
2864
+ and last_cmp_stmt_0.src.op == last_cmp_stmt_1.src.op
2865
+ and last_cmp_stmt_0.src.operands[1].likes(last_cmp_stmt_1.src.operands[1])
2866
+ )
2867
+
2868
+ def _fix_abnormal_switch_case_heads_case1(
2869
+ self,
2870
+ ail_graph: networkx.DiGraph,
2871
+ indirect_jump_node: ailment.Block,
2872
+ intended_head: ailment.Block,
2873
+ other_heads: list[ailment.Block],
2874
+ overlap: int,
2875
+ ) -> None:
2876
+ self._fix_abnormal_switch_case_heads_case2(
2877
+ ail_graph,
2878
+ indirect_jump_node,
2879
+ intended_head,
2880
+ other_heads,
2881
+ intended_head_split_insns=overlap,
2882
+ other_head_split_insns=overlap,
2883
+ )
2884
+
2885
+ def _fix_abnormal_switch_case_heads_case2(
2886
+ self,
2887
+ ail_graph: networkx.DiGraph,
2888
+ indirect_jump_node: ailment.Block,
2889
+ intended_head: ailment.Block,
2890
+ other_heads: list[ailment.Block],
2891
+ intended_head_split_insns: int = 1,
2892
+ other_head_split_insns: int = 0,
2893
+ ) -> None:
2894
+
2895
+ # split the intended head into two
2896
+ intended_head_block = self.project.factory.block(intended_head.addr, size=intended_head.original_size)
2897
+ split_ins_addr = intended_head_block.instruction_addrs[-intended_head_split_insns]
2898
+ # note that the two blocks can be fully overlapping, so block_0 will be empty...
2899
+ intended_head_block_0 = (
2900
+ self.project.factory.block(intended_head.addr, size=split_ins_addr - intended_head.addr)
2901
+ if split_ins_addr != intended_head.addr
2902
+ else None
2903
+ )
2904
+ intended_head_block_1 = self.project.factory.block(
2905
+ split_ins_addr, size=intended_head.addr + intended_head.original_size - split_ins_addr
2906
+ )
2907
+ intended_head_0 = self._convert_vex(intended_head_block_0) if intended_head_block_0 is not None else None
2908
+ intended_head_1 = self._convert_vex(intended_head_block_1)
2909
+
2910
+ # corner-case: the last statement of intended_head might have been patched by _remove_redundant_jump_blocks. we
2911
+ # detect such case and fix it in intended_head_1
2912
+ self._remove_redundant_jump_blocks_repatch_relifted_block(intended_head, intended_head_1)
2913
+
2914
+ # adjust the graph accordingly
2915
+ preds = list(ail_graph.predecessors(intended_head))
2916
+ succs = list(ail_graph.successors(intended_head))
2917
+ ail_graph.remove_node(intended_head)
2918
+
2919
+ if intended_head_0 is None:
2920
+ # perfect overlap; the first block is empty
2921
+ for pred in preds:
2922
+ if pred is intended_head:
2923
+ ail_graph.add_edge(intended_head_1, intended_head_1)
2924
+ else:
2925
+ ail_graph.add_edge(pred, intended_head_1)
2926
+ for succ in succs:
2927
+ if succ is intended_head:
2928
+ ail_graph.add_edge(intended_head_1, intended_head_1)
2929
+ else:
2930
+ ail_graph.add_edge(intended_head_1, succ)
2931
+ else:
2932
+ ail_graph.add_edge(intended_head_0, intended_head_1)
2933
+ for pred in preds:
2934
+ if pred is intended_head:
2935
+ ail_graph.add_edge(intended_head_1, intended_head_0)
2936
+ else:
2937
+ ail_graph.add_edge(pred, intended_head_0)
2938
+ for succ in succs:
2939
+ if succ is intended_head:
2940
+ ail_graph.add_edge(intended_head_1, intended_head_0)
2941
+ else:
2942
+ ail_graph.add_edge(intended_head_1, succ)
2943
+
2944
+ # split other heads
2945
+ for o in other_heads:
2946
+ if other_head_split_insns > 0:
2947
+ o_block = self.project.factory.block(o.addr, size=o.original_size)
2948
+ o_split_addr = o_block.instruction_addrs[-other_head_split_insns]
2949
+ new_o_block = (
2950
+ self.project.factory.block(o.addr, size=o_split_addr - o.addr) if o_split_addr != o.addr else None
2951
+ )
2952
+ new_head = self._convert_vex(new_o_block) if new_o_block is not None else None
2953
+ else:
2954
+ new_head = o
2955
+
2956
+ if new_head is None:
2957
+ # the head is removed - let's replace it with a jump to the target
2958
+ jump_stmt = ailment.Stmt.Jump(
2959
+ None,
2960
+ ailment.Expr.Const(None, None, intended_head_1.addr, self.project.arch.bits),
2961
+ target_idx=intended_head_1.idx,
2962
+ ins_addr=o.addr,
2963
+ )
2964
+ new_head = ailment.Block(o.addr, 1, statements=[jump_stmt], idx=o.idx)
2965
+ else:
2966
+ if (
2967
+ new_head.statements
2968
+ and isinstance(new_head.statements[-1], ailment.Stmt.Jump)
2969
+ and isinstance(new_head.statements[-1].target, ailment.Expr.Const)
2970
+ ):
2971
+ # update the jump target
2972
+ new_head.statements[-1] = ailment.Stmt.Jump(
2973
+ new_head.statements[-1].idx,
2974
+ ailment.Expr.Const(None, None, intended_head_1.addr, self.project.arch.bits),
2975
+ target_idx=intended_head_1.idx,
2976
+ **new_head.statements[-1].tags,
2977
+ )
2978
+
2979
+ # adjust the graph accordingly
2980
+ preds = list(ail_graph.predecessors(o))
2981
+ succs = list(ail_graph.successors(o))
2982
+ ail_graph.remove_node(o)
2983
+ for pred in preds:
2984
+ if pred is o:
2985
+ ail_graph.add_edge(new_head, new_head)
2986
+ else:
2987
+ ail_graph.add_edge(pred, new_head)
2988
+ for succ in succs:
2989
+ if succ is o:
2990
+ ail_graph.add_edge(new_head, new_head)
2991
+ elif succ is indirect_jump_node:
2992
+ ail_graph.add_edge(new_head, intended_head_1)
2993
+ else:
2994
+ # it should be going to the default node. ignore it
2995
+ pass
2996
+
2997
+ def _fix_abnormal_switch_case_heads_case3(
2998
+ self, indirect_jump_node: ailment.Block, other_heads: list[ailment.Block]
2999
+ ) -> None:
3000
+ # remove all edges from other_heads to the indirect jump node
3001
+ for other_head in other_heads:
3002
+ # delay the edge removal so that we don't mess up the SSA analysis
3003
+ self.edges_to_remove.append(
3004
+ ((other_head.addr, other_head.idx), (indirect_jump_node.addr, indirect_jump_node.idx))
3005
+ )
3006
+
3007
+ @staticmethod
3008
+ def _remove_redundant_jump_blocks(ail_graph):
3009
+ def first_conditional_jump(block: ailment.Block) -> ailment.Stmt.ConditionalJump | None:
3010
+ for stmt in block.statements:
3011
+ if isinstance(stmt, ailment.Stmt.ConditionalJump):
3012
+ return stmt
3013
+ return None
3014
+
3015
+ def patch_conditional_jump_target(cond_jump_stmt: ailment.Stmt.ConditionalJump, old_addr: int, new_addr: int):
3016
+ if (
3017
+ isinstance(cond_jump_stmt.true_target, ailment.Expr.Const)
3018
+ and cond_jump_stmt.true_target.value == old_addr
3019
+ ):
3020
+ cond_jump_stmt.true_target.value = new_addr
3021
+ if (
3022
+ isinstance(cond_jump_stmt.false_target, ailment.Expr.Const)
3023
+ and cond_jump_stmt.false_target.value == old_addr
3024
+ ):
3025
+ cond_jump_stmt.false_target.value = new_addr
3026
+
3027
+ # note that blocks don't have labels inserted at this point
3028
+ for node in list(ail_graph.nodes):
3029
+ if (
3030
+ len(node.statements) == 1
3031
+ and isinstance(node.statements[0], ailment.Stmt.Jump)
3032
+ and isinstance(node.statements[0].target, ailment.Expr.Const)
3033
+ ):
3034
+ jump_target = node.statements[0].target.value
3035
+ succs = list(ail_graph.successors(node))
3036
+ if len(succs) == 1 and succs[0].addr == jump_target:
3037
+ preds = list(ail_graph.predecessors(node))
3038
+ if len(preds) == 1 and ail_graph.out_degree[preds[0]] == 2:
3039
+ # remove this node
3040
+ for pred in preds:
3041
+ if pred.statements:
3042
+ last_stmt = pred.statements[-1]
3043
+ if (
3044
+ isinstance(last_stmt, ailment.Stmt.Jump)
3045
+ and isinstance(last_stmt.target, ailment.Expr.Const)
3046
+ and last_stmt.target.value == node.addr
3047
+ ):
3048
+ last_stmt.target.value = succs[0].addr
3049
+ elif isinstance(last_stmt, ailment.Stmt.ConditionalJump):
3050
+ patch_conditional_jump_target(last_stmt, node.addr, succs[0].addr)
3051
+ # if both branches jump to the same location, we replace it with a jump
3052
+ if (
3053
+ isinstance(last_stmt.true_target, ailment.Expr.Const)
3054
+ and isinstance(last_stmt.false_target, ailment.Expr.Const)
3055
+ and last_stmt.true_target.value == last_stmt.false_target.value
3056
+ ):
3057
+ last_stmt = ailment.Stmt.Jump(
3058
+ last_stmt.idx,
3059
+ last_stmt.true_target,
3060
+ target_idx=last_stmt.true_target.idx,
3061
+ ins_addr=last_stmt.tags["ins_addr"],
3062
+ )
3063
+ pred.statements[-1] = last_stmt
3064
+ first_cond_jump = first_conditional_jump(pred)
3065
+ if first_cond_jump is not None and first_cond_jump is not last_stmt:
3066
+ patch_conditional_jump_target(first_cond_jump, node.addr, succs[0].addr)
3067
+ ail_graph.add_edge(pred, succs[0])
3068
+ ail_graph.remove_node(node)
3069
+
3070
+ @staticmethod
3071
+ def _remove_redundant_jump_blocks_repatch_relifted_block(
3072
+ patched_block: ailment.Block, new_block: ailment.Block
3073
+ ) -> None:
3074
+ """
3075
+ The last statement of patched_block might have been patched by _remove_redundant_jump_blocks. In this case, we
3076
+ fix the last instruction for new_block, which is a newly lifted (from VEX) block that ends at the same address
3077
+ as patched_block.
3078
+
3079
+ :param patched_block: Previously patched block.
3080
+ :param new_block: Newly lifted block.
3081
+ """
3082
+
3083
+ if (
3084
+ isinstance(patched_block.statements[-1], ailment.Stmt.Jump)
3085
+ and isinstance(patched_block.statements[-1].target, ailment.Expr.Const)
3086
+ and isinstance(new_block.statements[-1], ailment.Stmt.Jump)
3087
+ and isinstance(new_block.statements[-1].target, ailment.Expr.Const)
3088
+ and not patched_block.statements[-1].likes(new_block.statements[-1])
3089
+ ):
3090
+ new_block.statements[-1].target = patched_block.statements[-1].target
3091
+ if (
3092
+ isinstance(patched_block.statements[-1], ailment.Stmt.ConditionalJump)
3093
+ and isinstance(patched_block.statements[-1].true_target, ailment.Expr.Const)
3094
+ and isinstance(patched_block.statements[-1].false_target, ailment.Expr.Const)
3095
+ and isinstance(new_block.statements[-1], ailment.Stmt.ConditionalJump)
3096
+ and isinstance(new_block.statements[-1].true_target, ailment.Expr.Const)
3097
+ and isinstance(new_block.statements[-1].false_target, ailment.Expr.Const)
3098
+ and not patched_block.statements[-1].likes(new_block.statements[-1])
3099
+ ):
3100
+ new_block.statements[-1].true_target = patched_block.statements[-1].true_target
3101
+ new_block.statements[-1].false_target = patched_block.statements[-1].false_target
3102
+
3103
+ @staticmethod
3104
+ def _insert_block_labels(ail_graph):
3105
+ for node in ail_graph.nodes:
3106
+ node: ailment.Block
3107
+ lbl = ailment.Stmt.Label(None, f"LABEL_{node.addr:x}", ins_addr=node.addr, block_idx=node.idx)
3108
+ node.statements.insert(0, lbl)
3109
+
3110
+ @staticmethod
3111
+ def _collect_externs(ail_graph, variable_kb):
3112
+ global_vars = variable_kb.variables.global_manager.get_variables()
3113
+ walker = ailment.AILBlockRewriter()
3114
+ variables = set()
3115
+
3116
+ def handle_expr(
3117
+ expr_idx: int,
3118
+ expr: ailment.expression.Expression,
3119
+ stmt_idx: int,
3120
+ stmt: ailment.statement.Statement | None,
3121
+ block: ailment.Block | None,
3122
+ ):
3123
+ for v in [
3124
+ getattr(expr, "variable", None),
3125
+ expr.tags.get("reference_variable", None) if hasattr(expr, "tags") else None,
3126
+ ]:
3127
+ if v and v in global_vars:
3128
+ variables.add(v)
3129
+ return ailment.AILBlockRewriter._handle_expr(walker, expr_idx, expr, stmt_idx, stmt, block)
3130
+
3131
+ def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block: ailment.Block | None):
3132
+ if stmt.variable and stmt.variable in global_vars:
3133
+ variables.add(stmt.variable)
3134
+ return ailment.AILBlockRewriter._handle_Store(walker, stmt_idx, stmt, block)
3135
+
3136
+ walker.stmt_handlers[ailment.statement.Store] = handle_Store
3137
+ walker._handle_expr = handle_expr
3138
+ AILGraphWalker(ail_graph, walker.walk).walk()
3139
+ return variables
3140
+
3141
+ @staticmethod
3142
+ def _collect_data_refs(ail_graph) -> dict[int, list[DataRefDesc]]:
3143
+ # pylint:disable=unused-argument
3144
+ walker = ailment.AILBlockRewriter()
3145
+ data_refs: dict[int, list[DataRefDesc]] = defaultdict(list)
3146
+
3147
+ def handle_Const(
3148
+ expr_idx: int,
3149
+ expr: ailment.expression.Const,
3150
+ stmt_idx: int,
3151
+ stmt: ailment.statement.Statement | None,
3152
+ block: ailment.Block | None,
3153
+ ):
3154
+ assert block is not None
3155
+ if isinstance(expr.value, int) and "ins_addr" in expr.tags:
3156
+ data_refs[block.addr].append(
3157
+ DataRefDesc(expr.value, 1, block.addr, stmt_idx, expr.tags["ins_addr"], MemoryDataSort.Unknown)
3158
+ )
3159
+ if "deref_src_addr" in expr.tags:
3160
+ data_refs[block.addr].append(
3161
+ DataRefDesc(
3162
+ expr.tags["deref_src_addr"],
3163
+ expr.size,
3164
+ block.addr,
3165
+ stmt_idx,
3166
+ expr.tags["ins_addr"],
3167
+ MemoryDataSort.Unknown,
3168
+ )
3169
+ )
3170
+ return expr
3171
+
3172
+ def handle_Load(
3173
+ expr_idx: int,
3174
+ expr: ailment.expression.Load,
3175
+ stmt_idx: int,
3176
+ stmt: ailment.statement.Statement | None,
3177
+ block: ailment.Block | None,
3178
+ ):
3179
+ assert block is not None
3180
+ if isinstance(expr.addr, ailment.expression.Const):
3181
+ addr = expr.addr
3182
+ if isinstance(addr.value, int) and "ins_addr" in addr.tags:
3183
+ data_refs[block.addr].append(
3184
+ DataRefDesc(
3185
+ addr.value,
3186
+ expr.size,
3187
+ block.addr,
3188
+ stmt_idx,
3189
+ addr.tags["ins_addr"],
3190
+ MemoryDataSort.Integer if expr.size == 4 else MemoryDataSort.Unknown,
3191
+ )
3192
+ )
3193
+ if "deref_src_addr" in addr.tags:
3194
+ data_refs[block.addr].append(
3195
+ DataRefDesc(
3196
+ addr.tags["deref_src_addr"],
3197
+ expr.size,
3198
+ block.addr,
3199
+ stmt_idx,
3200
+ addr.tags["ins_addr"],
3201
+ MemoryDataSort.Integer if expr.size == 4 else MemoryDataSort.Unknown,
3202
+ )
3203
+ )
3204
+ return expr
3205
+
3206
+ return ailment.AILBlockRewriter._handle_Load(walker, expr_idx, expr, stmt_idx, stmt, block)
3207
+
3208
+ def handle_Store(stmt_idx: int, stmt: ailment.statement.Store, block: ailment.Block | None):
3209
+ assert block is not None
3210
+ if isinstance(stmt.addr, ailment.expression.Const):
3211
+ addr = stmt.addr
3212
+ if isinstance(addr.value, int) and "ins_addr" in addr.tags:
3213
+ data_refs[block.addr].append(
3214
+ DataRefDesc(
3215
+ addr.value,
3216
+ stmt.size,
3217
+ block.addr,
3218
+ stmt_idx,
3219
+ addr.tags["ins_addr"],
3220
+ MemoryDataSort.Integer if stmt.size == 4 else MemoryDataSort.Unknown,
3221
+ )
3222
+ )
3223
+ if "deref_src_addr" in addr.tags:
3224
+ data_refs[block.addr].append(
3225
+ DataRefDesc(
3226
+ addr.tags["deref_src_addr"],
3227
+ stmt.size,
3228
+ block.addr,
3229
+ stmt_idx,
3230
+ addr.tags["ins_addr"],
3231
+ MemoryDataSort.Integer if stmt.size == 4 else MemoryDataSort.Unknown,
3232
+ )
3233
+ )
3234
+ return stmt
3235
+
3236
+ return ailment.AILBlockRewriter._handle_Store(walker, stmt_idx, stmt, block)
3237
+
3238
+ walker.stmt_handlers[ailment.statement.Store] = handle_Store
3239
+ walker.expr_handlers[ailment.expression.Load] = handle_Load
3240
+ walker.expr_handlers[ailment.expression.Const] = handle_Const
3241
+ AILGraphWalker(ail_graph, walker.walk).walk()
3242
+ return data_refs
3243
+
3244
+ def _next_atom(self) -> int:
3245
+ return self._ail_manager.next_atom()
3246
+
3247
+ def parse_variable_addr(self, addr: ailment.Expr.Expression) -> tuple[Any, Any]:
3248
+ if isinstance(addr, ailment.Expr.Const):
3249
+ return addr, 0
3250
+ if isinstance(addr, ailment.Expr.BinaryOp) and addr.op == "Add":
3251
+ op0, op1 = addr.operands
3252
+ if (
3253
+ isinstance(op0, ailment.Expr.Const)
3254
+ and self.project.loader.find_object_containing(op0.value_int) is not None
3255
+ ):
3256
+ return op0, op1
3257
+ if (
3258
+ isinstance(op1, ailment.Expr.Const)
3259
+ and self.project.loader.find_object_containing(op1.value_int) is not None
3260
+ ):
3261
+ return op1, op0
3262
+ return op0, op1 # best-effort guess
3263
+ return None, None
3264
+
3265
+ def new_block_addr(self) -> int:
3266
+ """
3267
+ Return a block address that does not conflict with any existing blocks.
3268
+
3269
+ :return: The block address.
3270
+ """
3271
+ if self._new_block_addrs:
3272
+ new_addr = max(self._new_block_addrs) + 1
3273
+ else:
3274
+ new_addr = max(self.function.block_addrs_set) + 2048
3275
+ self._new_block_addrs.add(new_addr)
3276
+ return new_addr
3277
+
3278
+ @staticmethod
3279
+ @timethis
3280
+ def remove_empty_nodes(graph: networkx.DiGraph) -> networkx.DiGraph:
3281
+ def handle_node(node: ailment.Block):
3282
+ if not node.statements:
3283
+ preds = [pred for pred in graph.predecessors(node) if pred is not node]
3284
+ succs = [succ for succ in graph.successors(node) if succ is not node]
3285
+ if len(preds) == 1 and len(succs) == 1:
3286
+ pred = preds[0]
3287
+ succ = succs[0]
3288
+ value_updated = False
3289
+ # update the last statement of pred
3290
+ if pred.statements and isinstance(pred.statements[-1], ailment.Stmt.ConditionalJump):
3291
+ last_stmt = pred.statements[-1]
3292
+ if (
3293
+ isinstance(last_stmt.true_target, ailment.Expr.Const)
3294
+ and last_stmt.true_target.value == node.addr
3295
+ ):
3296
+ last_stmt.true_target.value = succ.addr
3297
+ value_updated = True
3298
+ if (
3299
+ isinstance(last_stmt.false_target, ailment.Expr.Const)
3300
+ and last_stmt.false_target.value == node.addr
3301
+ ):
3302
+ last_stmt.false_target.value = succ.addr
3303
+ value_updated = True
3304
+
3305
+ if value_updated:
3306
+ graph.add_edge(pred, succ)
3307
+ raise RemoveNodeNotice
3308
+ elif len(preds) >= 1 and len(succs) == 1:
3309
+ succ = succs[0]
3310
+ branch_updates = 0
3311
+ for pred in preds:
3312
+ # test how many last statements of pred can potentially be updated
3313
+ if pred.statements and isinstance(pred.statements[-1], ailment.Stmt.ConditionalJump):
3314
+ last_stmt = pred.statements[-1]
3315
+ if (
3316
+ isinstance(last_stmt.true_target, ailment.Expr.Const)
3317
+ and last_stmt.true_target.value == node.addr
3318
+ ):
3319
+ branch_updates += 1
3320
+ if (
3321
+ isinstance(last_stmt.false_target, ailment.Expr.Const)
3322
+ and last_stmt.false_target.value == node.addr
3323
+ ):
3324
+ branch_updates += 1
3325
+
3326
+ if branch_updates == len(preds):
3327
+ # actually do the update
3328
+ for pred in preds:
3329
+ graph.add_edge(pred, succ)
3330
+ if pred.statements and isinstance(pred.statements[-1], ailment.Stmt.ConditionalJump):
3331
+ last_stmt = pred.statements[-1]
3332
+ if (
3333
+ isinstance(last_stmt.true_target, ailment.Expr.Const)
3334
+ and last_stmt.true_target.value == node.addr
3335
+ ):
3336
+ last_stmt.true_target.value = succ.addr
3337
+ if (
3338
+ isinstance(last_stmt.false_target, ailment.Expr.Const)
3339
+ and last_stmt.false_target.value == node.addr
3340
+ ):
3341
+ last_stmt.false_target.value = succ.addr
3342
+ raise RemoveNodeNotice
3343
+ elif not preds or not succs:
3344
+ raise RemoveNodeNotice
3345
+
3346
+ AILGraphWalker(graph, handle_node, replace_nodes=True).walk()
3347
+ return graph
3348
+
3349
+ def _find_regs_compared_against_sp(self, func_graph):
3350
+ # TODO: Implement this function for architectures beyond amd64
3351
+ extra_regs = set()
3352
+ if self.project.arch.name == "AMD64":
3353
+ for node in func_graph.nodes:
3354
+ block = self.project.factory.block(node.addr, size=node.size).capstone
3355
+ for insn in block.insns:
3356
+ if insn.mnemonic == "cmp":
3357
+ capstone_reg_offset = None
3358
+ if (
3359
+ insn.operands[0].type == capstone.x86.X86_OP_REG
3360
+ and insn.operands[0].reg == capstone.x86.X86_REG_RSP
3361
+ and insn.operands[1].type == capstone.x86.X86_OP_REG
3362
+ ):
3363
+ capstone_reg_offset = insn.operands[1].reg
3364
+ elif (
3365
+ insn.operands[1].type == capstone.x86.X86_OP_REG
3366
+ and insn.operands[1].reg == capstone.x86.X86_REG_RSP
3367
+ and insn.operands[0].type == capstone.x86.X86_OP_REG
3368
+ ):
3369
+ capstone_reg_offset = insn.operands[0].reg
3370
+
3371
+ if capstone_reg_offset is not None:
3372
+ reg_name = insn.reg_name(capstone_reg_offset)
3373
+ extra_regs.add(self.project.arch.registers[reg_name][0])
3374
+
3375
+ return extra_regs
3376
+
3377
+ def _rewrite_rust_probestack_call(self, ail_graph):
3378
+ for node in ail_graph:
3379
+ if not node.statements or ail_graph.out_degree[node] != 1:
3380
+ continue
3381
+ last_stmt = node.statements[-1]
3382
+ if isinstance(last_stmt, ailment.Stmt.Call) and isinstance(last_stmt.target, ailment.Expr.Const):
3383
+ func = (
3384
+ self.project.kb.functions.get_by_addr(last_stmt.target.value)
3385
+ if self.project.kb.functions.contains_addr(last_stmt.target.value)
3386
+ else None
3387
+ )
3388
+ if func is not None and func.info.get("is_rust_probestack", False) is True:
3389
+ # get rid of this call
3390
+ node.statements = node.statements[:-1]
3391
+ if self.project.arch.call_pushes_ret and node.statements:
3392
+ last_stmt = node.statements[-1]
3393
+ succ = next(iter(ail_graph.successors(node)))
3394
+ if (
3395
+ isinstance(last_stmt, ailment.Stmt.Store)
3396
+ and isinstance(last_stmt.addr, ailment.Expr.StackBaseOffset)
3397
+ and isinstance(last_stmt.addr.offset, int)
3398
+ and last_stmt.addr.offset < 0
3399
+ and isinstance(last_stmt.data, ailment.Expr.Const)
3400
+ and last_stmt.data.value == succ.addr
3401
+ ) or (
3402
+ isinstance(last_stmt, ailment.Stmt.Assignment)
3403
+ and last_stmt.dst.was_stack
3404
+ and last_stmt.dst.stack_offset < 0
3405
+ and isinstance(last_stmt.src, ailment.Expr.Const)
3406
+ and last_stmt.src.value == succ.addr
3407
+ ):
3408
+ # remove the statement that pushes the return address
3409
+ node.statements = node.statements[:-1]
3410
+ break
3411
+ return ail_graph
3412
+
3413
+ def _rewrite_windows_chkstk_call(self, ail_graph) -> networkx.DiGraph:
3414
+ if not (self.project.simos is not None and self.project.simos.name == "Win32"):
3415
+ return ail_graph
3416
+
3417
+ for node in ail_graph:
3418
+ if not node.statements or ail_graph.out_degree[node] != 1:
3419
+ continue
3420
+ last_stmt = node.statements[-1]
3421
+ if isinstance(last_stmt, ailment.Stmt.Call) and isinstance(last_stmt.target, ailment.Expr.Const):
3422
+ func = (
3423
+ self.project.kb.functions.get_by_addr(last_stmt.target.value)
3424
+ if self.project.kb.functions.contains_addr(last_stmt.target.value)
3425
+ else None
3426
+ )
3427
+ if func is not None and (func.name == "__chkstk" or func.info.get("is_alloca_probe", False) is True):
3428
+ # get rid of this call
3429
+ node.statements = node.statements[:-1]
3430
+ if self.project.arch.call_pushes_ret and node.statements:
3431
+ last_stmt = node.statements[-1]
3432
+ succ = next(iter(ail_graph.successors(node)))
3433
+ if (
3434
+ isinstance(last_stmt, ailment.Stmt.Store)
3435
+ and isinstance(last_stmt.addr, ailment.Expr.StackBaseOffset)
3436
+ and isinstance(last_stmt.addr.offset, int)
3437
+ and last_stmt.addr.offset < 0
3438
+ and isinstance(last_stmt.data, ailment.Expr.Const)
3439
+ and last_stmt.data.value == succ.addr
3440
+ ) or (
3441
+ isinstance(last_stmt, ailment.Stmt.Assignment)
3442
+ and last_stmt.dst.was_stack
3443
+ and last_stmt.dst.stack_offset < 0
3444
+ and isinstance(last_stmt.src, ailment.Expr.Const)
3445
+ and last_stmt.src.value == succ.addr
3446
+ ):
3447
+ # remove the statement that pushes the return address
3448
+ node.statements = node.statements[:-1]
3449
+ break
3450
+ return ail_graph
3451
+
3452
+ def _rewrite_alloca(self, ail_graph):
3453
+ # pylint:disable=too-many-boolean-expressions
3454
+ alloca_node = None
3455
+ sp_equal_to = None
3456
+
3457
+ for node in ail_graph:
3458
+ if ail_graph.in_degree[node] == 2 and ail_graph.out_degree[node] == 2:
3459
+ succs = ail_graph.successors(node)
3460
+ if node in succs and len(node.statements) >= 6:
3461
+ # self loop!
3462
+ stmt0 = node.statements[1] # skip the LABEL statement
3463
+ stmt1 = node.statements[2]
3464
+ last_stmt = node.statements[-1]
3465
+ if (
3466
+ (
3467
+ isinstance(stmt0, ailment.Stmt.Assignment)
3468
+ and isinstance(stmt0.dst, ailment.Expr.Register)
3469
+ and isinstance(stmt0.src, ailment.Expr.StackBaseOffset)
3470
+ and stmt0.src.offset == -0x1000
3471
+ )
3472
+ and (
3473
+ isinstance(stmt1, ailment.Stmt.Store)
3474
+ and isinstance(stmt1.addr, ailment.Expr.StackBaseOffset)
3475
+ and stmt1.addr.offset == -0x1000
3476
+ and isinstance(stmt1.data, ailment.Expr.Load)
3477
+ and isinstance(stmt1.data.addr, ailment.Expr.StackBaseOffset)
3478
+ and stmt1.data.addr.offset == -0x1000
3479
+ )
3480
+ and (
3481
+ isinstance(last_stmt, ailment.Stmt.ConditionalJump)
3482
+ and isinstance(last_stmt.condition, ailment.Expr.BinaryOp)
3483
+ and last_stmt.condition.op == "CmpEQ"
3484
+ and isinstance(last_stmt.condition.operands[0], ailment.Expr.StackBaseOffset)
3485
+ and last_stmt.condition.operands[0].offset == -0x1000
3486
+ and isinstance(last_stmt.condition.operands[1], ailment.Expr.Register)
3487
+ and isinstance(last_stmt.false_target, ailment.Expr.Const)
3488
+ and last_stmt.false_target.value == node.addr
3489
+ )
3490
+ ):
3491
+ # found it!
3492
+ assert self.project.arch.sp_offset is not None
3493
+ alloca_node = node
3494
+ sp_equal_to = ailment.Expr.BinaryOp(
3495
+ None,
3496
+ "Sub",
3497
+ [
3498
+ ailment.Expr.Register(None, None, self.project.arch.sp_offset, self.project.arch.bits),
3499
+ last_stmt.condition.operands[1],
3500
+ ],
3501
+ False,
3502
+ )
3503
+ break
3504
+
3505
+ if alloca_node is not None and sp_equal_to is not None:
3506
+ stmt0 = alloca_node.statements[1]
3507
+ statements: list[ailment.Statement] = [
3508
+ ailment.Stmt.Call(stmt0.idx, "alloca", args=[sp_equal_to], **stmt0.tags)
3509
+ ]
3510
+ new_node = ailment.Block(alloca_node.addr, alloca_node.original_size, statements=statements)
3511
+ # replace the node
3512
+ preds = [pred for pred in ail_graph.predecessors(alloca_node) if pred is not alloca_node]
3513
+ succs = [succ for succ in ail_graph.successors(alloca_node) if succ is not alloca_node]
3514
+ ail_graph.remove_node(alloca_node)
3515
+ for pred in preds:
3516
+ ail_graph.add_edge(pred, new_node)
3517
+ for succ in succs:
3518
+ ail_graph.add_edge(new_node, succ)
3519
+
3520
+ def _collect_callsite_prototypes(self) -> dict[int, list[tuple[list[SimType | None], SimType | None]]]:
3521
+
3522
+ assert self.variable_kb is not None
3523
+
3524
+ variables = self.variable_kb.variables[self.function.addr]
3525
+ func_proto_candidates: defaultdict[int, list[tuple[list[SimType | None], SimType | None]]] = defaultdict(list)
3526
+
3527
+ def _handle_Call_stmt_or_expr(call_: ailment.Stmt.Call):
3528
+ assert self.arg_vvars is not None
3529
+
3530
+ if (
3531
+ isinstance(call_.target, ailment.Expr.Const)
3532
+ and call_.tags.get("is_prototype_guessed", True)
3533
+ and call_.args is not None
3534
+ ):
3535
+ # derive the actual prototype
3536
+ arg_types = []
3537
+ for arg_expr in call_.args:
3538
+ arg_type = None
3539
+ if hasattr(arg_expr, "variable") and arg_expr.variable is not None:
3540
+ # the type is type(a)
3541
+ t = None
3542
+ if isinstance(arg_expr, ailment.Expr.VirtualVariable):
3543
+ # a function arg
3544
+ for func_arg_vvar, func_arg_simvar in self.arg_vvars.values():
3545
+ if (
3546
+ arg_expr.likes(func_arg_vvar)
3547
+ and func_arg_simvar is not None
3548
+ and func_arg_simvar.ident.startswith("arg_")
3549
+ ):
3550
+ # FIXME: Parsing arg_idx out of argument ident is hacky
3551
+ arg_idx = int(func_arg_simvar.ident[4:])
3552
+ assert self.function.prototype is not None
3553
+ if arg_idx < len(self.function.prototype.args):
3554
+ t = self.function.prototype.args[arg_idx]
3555
+ break
3556
+
3557
+ if t is None:
3558
+ # maybe not a function arg
3559
+ v = arg_expr.variable
3560
+ if v is not None:
3561
+ t = variables.get_variable_type(v)
3562
+
3563
+ if t is not None:
3564
+ arg_type = t
3565
+ elif isinstance(arg_expr, ailment.Expr.UnaryOp) and arg_expr.op == "Reference":
3566
+ # &a; the type becomes a pointer to type(a)
3567
+ inner = arg_expr.operand
3568
+ v = inner.variable
3569
+ if v is not None:
3570
+ t = variables.get_variable_type(v)
3571
+ if t is not None:
3572
+ arg_type = SimTypePointer(t)
3573
+
3574
+ arg_types.append(arg_type)
3575
+
3576
+ func_proto_candidates[call_.target.value_int].append((arg_types, None))
3577
+
3578
+ # pylint:disable=unused-argument
3579
+ def _handle_Call(stmt_idx: int, stmt: ailment.Stmt.Call, block: ailment.Block | None):
3580
+ _handle_Call_stmt_or_expr(stmt)
3581
+
3582
+ # pylint:disable=unused-argument
3583
+ def _handle_CallExpr(
3584
+ expr_idx: int,
3585
+ expr: ailment.Stmt.Call,
3586
+ stmt_idx: int,
3587
+ stmt: ailment.Stmt.Statement | None,
3588
+ block: ailment.Block | None,
3589
+ ):
3590
+ _handle_Call_stmt_or_expr(expr)
3591
+
3592
+ def _visit_ail_node(node: ailment.Block):
3593
+ w = AILBlockViewer()
3594
+ w.stmt_handlers[ailment.Stmt.Call] = _handle_Call
3595
+ w.expr_handlers[ailment.Stmt.Call] = _handle_CallExpr
3596
+ w.walk(node)
3597
+
3598
+ AILGraphWalker(self._ail_graph, _visit_ail_node).walk()
3599
+
3600
+ return dict(func_proto_candidates)
3601
+
3602
+ def _constrain_callee_prototypes(self):
3603
+ func_proto_candidates = self._collect_callsite_prototypes()
3604
+
3605
+ default_arg_type = SimTypeLongLong if self.project.arch.bits == 64 else SimTypeInt
3606
+
3607
+ for func_addr, protos in func_proto_candidates.items():
3608
+ if not self.kb.functions.contains_addr(func_addr):
3609
+ continue
3610
+ func = self.kb.functions.get_by_addr(func_addr)
3611
+ if func.prototype is not None and func.is_prototype_guessed is False:
3612
+ # already has a "good" prototype; don't overwrite it
3613
+ continue
3614
+
3615
+ # TODO: merge the return type
3616
+ # ret_types = [proto[1] for proto in protos]
3617
+ args_list = [proto[0] for proto in protos]
3618
+
3619
+ # for each argument, we find the most precise type
3620
+ arg_count = min(len(args) for args in args_list)
3621
+ arg_result = {}
3622
+
3623
+ for arg_i in range(arg_count): # pylint:disable=consider-using-enumerate
3624
+ all_args: list[SimType] = [ # type: ignore
3625
+ args_list[i][arg_i] for i in range(len(args_list)) if args_list[i][arg_i] is not None
3626
+ ]
3627
+ if not all_args:
3628
+ continue
3629
+ # TODO: Implement a better logic to find the precise type
3630
+ precise_types = []
3631
+ for a in all_args:
3632
+ if isinstance(a, (SimTypePointer, SimStruct, SimTypeArray, SimCppClass)):
3633
+ precise_types.append(a)
3634
+ if len(precise_types) == 1:
3635
+ arg_result[arg_i] = precise_types[0]
3636
+
3637
+ if arg_result:
3638
+ # build a new function prototype
3639
+ new_arg_types = []
3640
+ func_arg_count = (
3641
+ len(func.prototype.args) if func.prototype is not None and func.prototype.args else max(arg_result)
3642
+ )
3643
+ for i in range(func_arg_count):
3644
+ if i in arg_result:
3645
+ new_arg_types.append(arg_result[i])
3646
+ else:
3647
+ if func.prototype is not None:
3648
+ new_arg_types.append(func.prototype.args[i])
3649
+ else:
3650
+ new_arg_types.append(default_arg_type())
3651
+ new_type = SimTypeFunction(
3652
+ new_arg_types,
3653
+ func.prototype.returnty if func.prototype is not None else default_arg_type(),
3654
+ label=func.prototype.label if func.prototype is not None else None,
3655
+ arg_names=func.prototype.arg_names if func.prototype is not None else None,
3656
+ variadic=func.prototype.variadic if func.prototype is not None else False,
3657
+ ).with_arch(self.project.arch)
3658
+ func.prototype = new_type
3659
+ func.is_prototype_guessed = False
3660
+
3661
+
3662
+ register_analysis(Clinic, "Clinic")