angr 9.2.158__cp310-abi3-manylinux2014_aarch64.whl

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

Potentially problematic release.


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

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