angr 9.2.103__py3-none-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 (1300) hide show
  1. angr/__init__.py +153 -0
  2. angr/__main__.py +59 -0
  3. angr/analyses/__init__.py +46 -0
  4. angr/analyses/analysis.py +359 -0
  5. angr/analyses/backward_slice.py +691 -0
  6. angr/analyses/binary_optimizer.py +683 -0
  7. angr/analyses/bindiff.py +1251 -0
  8. angr/analyses/boyscout.py +77 -0
  9. angr/analyses/callee_cleanup_finder.py +75 -0
  10. angr/analyses/calling_convention.py +956 -0
  11. angr/analyses/cdg.py +197 -0
  12. angr/analyses/cfg/__init__.py +11 -0
  13. angr/analyses/cfg/cfb.py +436 -0
  14. angr/analyses/cfg/cfg.py +73 -0
  15. angr/analyses/cfg/cfg_arch_options.py +82 -0
  16. angr/analyses/cfg/cfg_base.py +2917 -0
  17. angr/analyses/cfg/cfg_emulated.py +3570 -0
  18. angr/analyses/cfg/cfg_fast.py +5053 -0
  19. angr/analyses/cfg/cfg_fast_soot.py +669 -0
  20. angr/analyses/cfg/cfg_job_base.py +204 -0
  21. angr/analyses/cfg/indirect_jump_resolvers/__init__.py +8 -0
  22. angr/analyses/cfg/indirect_jump_resolvers/amd64_elf_got.py +63 -0
  23. angr/analyses/cfg/indirect_jump_resolvers/amd64_pe_iat.py +52 -0
  24. angr/analyses/cfg/indirect_jump_resolvers/arm_elf_fast.py +151 -0
  25. angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +141 -0
  26. angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +68 -0
  27. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +2368 -0
  28. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +517 -0
  29. angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +26 -0
  30. angr/analyses/cfg/indirect_jump_resolvers/resolver.py +74 -0
  31. angr/analyses/cfg/indirect_jump_resolvers/x86_elf_pic_plt.py +93 -0
  32. angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +51 -0
  33. angr/analyses/cfg_slice_to_sink/__init__.py +2 -0
  34. angr/analyses/cfg_slice_to_sink/cfg_slice_to_sink.py +117 -0
  35. angr/analyses/cfg_slice_to_sink/graph.py +84 -0
  36. angr/analyses/cfg_slice_to_sink/transitions.py +25 -0
  37. angr/analyses/class_identifier.py +62 -0
  38. angr/analyses/code_tagging.py +123 -0
  39. angr/analyses/complete_calling_conventions.py +424 -0
  40. angr/analyses/congruency_check.py +384 -0
  41. angr/analyses/data_dep/__init__.py +2 -0
  42. angr/analyses/data_dep/data_dependency_analysis.py +605 -0
  43. angr/analyses/data_dep/dep_nodes.py +170 -0
  44. angr/analyses/data_dep/sim_act_location.py +46 -0
  45. angr/analyses/datagraph_meta.py +105 -0
  46. angr/analyses/ddg.py +1695 -0
  47. angr/analyses/decompiler/__init__.py +13 -0
  48. angr/analyses/decompiler/ail_simplifier.py +1408 -0
  49. angr/analyses/decompiler/ailgraph_walker.py +48 -0
  50. angr/analyses/decompiler/block_io_finder.py +293 -0
  51. angr/analyses/decompiler/block_similarity.py +188 -0
  52. angr/analyses/decompiler/block_simplifier.py +434 -0
  53. angr/analyses/decompiler/call_counter.py +43 -0
  54. angr/analyses/decompiler/callsite_maker.py +403 -0
  55. angr/analyses/decompiler/ccall_rewriters/__init__.py +6 -0
  56. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +489 -0
  57. angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +19 -0
  58. angr/analyses/decompiler/clinic.py +2166 -0
  59. angr/analyses/decompiler/condition_processor.py +1184 -0
  60. angr/analyses/decompiler/decompilation_cache.py +38 -0
  61. angr/analyses/decompiler/decompilation_options.py +274 -0
  62. angr/analyses/decompiler/decompiler.py +544 -0
  63. angr/analyses/decompiler/empty_node_remover.py +211 -0
  64. angr/analyses/decompiler/expression_counters.py +76 -0
  65. angr/analyses/decompiler/expression_narrower.py +92 -0
  66. angr/analyses/decompiler/goto_manager.py +73 -0
  67. angr/analyses/decompiler/graph_region.py +413 -0
  68. angr/analyses/decompiler/jump_target_collector.py +36 -0
  69. angr/analyses/decompiler/jumptable_entry_condition_rewriter.py +66 -0
  70. angr/analyses/decompiler/optimization_passes/__init__.py +108 -0
  71. angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +144 -0
  72. angr/analyses/decompiler/optimization_passes/code_motion.py +360 -0
  73. angr/analyses/decompiler/optimization_passes/const_derefs.py +265 -0
  74. angr/analyses/decompiler/optimization_passes/cross_jump_reverter.py +108 -0
  75. angr/analyses/decompiler/optimization_passes/deadblock_remover.py +73 -0
  76. angr/analyses/decompiler/optimization_passes/div_simplifier.py +391 -0
  77. angr/analyses/decompiler/optimization_passes/engine_base.py +303 -0
  78. angr/analyses/decompiler/optimization_passes/expr_op_swapper.py +136 -0
  79. angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +91 -0
  80. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +386 -0
  81. angr/analyses/decompiler/optimization_passes/ite_expr_converter.py +226 -0
  82. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +189 -0
  83. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +757 -0
  84. angr/analyses/decompiler/optimization_passes/mod_simplifier.py +86 -0
  85. angr/analyses/decompiler/optimization_passes/multi_simplifier.py +227 -0
  86. angr/analyses/decompiler/optimization_passes/optimization_pass.py +397 -0
  87. angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +198 -0
  88. angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py +172 -0
  89. angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +219 -0
  90. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +448 -0
  91. angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +57 -0
  92. angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +121 -0
  93. angr/analyses/decompiler/optimization_passes/spilled_register_finder.py +18 -0
  94. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +293 -0
  95. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +110 -0
  96. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +281 -0
  97. angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +87 -0
  98. angr/analyses/decompiler/peephole_optimizations/__init__.py +69 -0
  99. angr/analyses/decompiler/peephole_optimizations/a_div_const_add_a_mul_n_div_const.py +38 -0
  100. angr/analyses/decompiler/peephole_optimizations/a_mul_const_div_shr_const.py +38 -0
  101. angr/analyses/decompiler/peephole_optimizations/a_shl_const_sub_a.py +31 -0
  102. angr/analyses/decompiler/peephole_optimizations/a_sub_a_div.py +25 -0
  103. angr/analyses/decompiler/peephole_optimizations/a_sub_a_div_const_mul_const.py +56 -0
  104. angr/analyses/decompiler/peephole_optimizations/a_sub_a_sub_n.py +19 -0
  105. angr/analyses/decompiler/peephole_optimizations/arm_cmpf.py +235 -0
  106. angr/analyses/decompiler/peephole_optimizations/base.py +120 -0
  107. angr/analyses/decompiler/peephole_optimizations/basepointeroffset_add_n.py +33 -0
  108. angr/analyses/decompiler/peephole_optimizations/basepointeroffset_and_mask.py +35 -0
  109. angr/analyses/decompiler/peephole_optimizations/bitwise_or_to_logical_or.py +34 -0
  110. angr/analyses/decompiler/peephole_optimizations/bool_expr_xor_1.py +27 -0
  111. angr/analyses/decompiler/peephole_optimizations/bswap.py +131 -0
  112. angr/analyses/decompiler/peephole_optimizations/cmpord_rewriter.py +72 -0
  113. angr/analyses/decompiler/peephole_optimizations/coalesce_same_cascading_ifs.py +27 -0
  114. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +91 -0
  115. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +43 -0
  116. angr/analyses/decompiler/peephole_optimizations/conv_a_sub0_shr_and.py +70 -0
  117. angr/analyses/decompiler/peephole_optimizations/conv_shl_shr.py +51 -0
  118. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +225 -0
  119. angr/analyses/decompiler/peephole_optimizations/extended_byte_and_mask.py +55 -0
  120. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +146 -0
  121. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +102 -0
  122. angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +159 -0
  123. angr/analyses/decompiler/peephole_optimizations/invert_negated_logical_conjuction_disjunction.py +50 -0
  124. angr/analyses/decompiler/peephole_optimizations/one_sub_bool.py +33 -0
  125. angr/analyses/decompiler/peephole_optimizations/remove_cascading_conversions.py +19 -0
  126. angr/analyses/decompiler/peephole_optimizations/remove_empty_if_body.py +45 -0
  127. angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py +26 -0
  128. angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +48 -0
  129. angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +160 -0
  130. angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_branch.py +29 -0
  131. angr/analyses/decompiler/peephole_optimizations/remove_redundant_ite_comparisons.py +54 -0
  132. angr/analyses/decompiler/peephole_optimizations/remove_redundant_nots.py +17 -0
  133. angr/analyses/decompiler/peephole_optimizations/remove_redundant_reinterprets.py +43 -0
  134. angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +44 -0
  135. angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts_around_comparators.py +40 -0
  136. angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +85 -0
  137. angr/analyses/decompiler/peephole_optimizations/rewrite_mips_gp_loads.py +47 -0
  138. angr/analyses/decompiler/peephole_optimizations/rol_ror.py +77 -0
  139. angr/analyses/decompiler/peephole_optimizations/sar_to_signed_div.py +105 -0
  140. angr/analyses/decompiler/peephole_optimizations/simplify_pc_relative_loads.py +37 -0
  141. angr/analyses/decompiler/peephole_optimizations/single_bit_cond_to_boolexpr.py +52 -0
  142. angr/analyses/decompiler/peephole_optimizations/single_bit_xor.py +26 -0
  143. angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py +133 -0
  144. angr/analyses/decompiler/redundant_label_remover.py +116 -0
  145. angr/analyses/decompiler/region_identifier.py +1098 -0
  146. angr/analyses/decompiler/region_simplifiers/__init__.py +1 -0
  147. angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py +93 -0
  148. angr/analyses/decompiler/region_simplifiers/cascading_ifs.py +81 -0
  149. angr/analyses/decompiler/region_simplifiers/expr_folding.py +606 -0
  150. angr/analyses/decompiler/region_simplifiers/goto.py +177 -0
  151. angr/analyses/decompiler/region_simplifiers/if_.py +142 -0
  152. angr/analyses/decompiler/region_simplifiers/ifelse.py +90 -0
  153. angr/analyses/decompiler/region_simplifiers/loop.py +135 -0
  154. angr/analyses/decompiler/region_simplifiers/node_address_finder.py +23 -0
  155. angr/analyses/decompiler/region_simplifiers/region_simplifier.py +211 -0
  156. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +644 -0
  157. angr/analyses/decompiler/region_simplifiers/switch_expr_simplifier.py +83 -0
  158. angr/analyses/decompiler/region_walker.py +23 -0
  159. angr/analyses/decompiler/return_maker.py +70 -0
  160. angr/analyses/decompiler/seq_to_blocks.py +19 -0
  161. angr/analyses/decompiler/sequence_walker.py +235 -0
  162. angr/analyses/decompiler/structured_codegen/__init__.py +10 -0
  163. angr/analyses/decompiler/structured_codegen/base.py +132 -0
  164. angr/analyses/decompiler/structured_codegen/c.py +3811 -0
  165. angr/analyses/decompiler/structured_codegen/dummy.py +14 -0
  166. angr/analyses/decompiler/structured_codegen/dwarf_import.py +186 -0
  167. angr/analyses/decompiler/structuring/__init__.py +15 -0
  168. angr/analyses/decompiler/structuring/dream.py +1225 -0
  169. angr/analyses/decompiler/structuring/phoenix.py +2546 -0
  170. angr/analyses/decompiler/structuring/recursive_structurer.py +186 -0
  171. angr/analyses/decompiler/structuring/structurer_base.py +954 -0
  172. angr/analyses/decompiler/structuring/structurer_nodes.py +414 -0
  173. angr/analyses/decompiler/utils.py +787 -0
  174. angr/analyses/disassembly.py +1302 -0
  175. angr/analyses/disassembly_utils.py +104 -0
  176. angr/analyses/dominance_frontier.py +39 -0
  177. angr/analyses/find_objects_static.py +203 -0
  178. angr/analyses/flirt.py +185 -0
  179. angr/analyses/forward_analysis/__init__.py +2 -0
  180. angr/analyses/forward_analysis/forward_analysis.py +527 -0
  181. angr/analyses/forward_analysis/job_info.py +64 -0
  182. angr/analyses/forward_analysis/visitors/__init__.py +4 -0
  183. angr/analyses/forward_analysis/visitors/call_graph.py +28 -0
  184. angr/analyses/forward_analysis/visitors/function_graph.py +85 -0
  185. angr/analyses/forward_analysis/visitors/graph.py +250 -0
  186. angr/analyses/forward_analysis/visitors/loop.py +28 -0
  187. angr/analyses/forward_analysis/visitors/single_node_graph.py +38 -0
  188. angr/analyses/identifier/__init__.py +1 -0
  189. angr/analyses/identifier/custom_callable.py +138 -0
  190. angr/analyses/identifier/errors.py +9 -0
  191. angr/analyses/identifier/func.py +57 -0
  192. angr/analyses/identifier/functions/__init__.py +36 -0
  193. angr/analyses/identifier/functions/atoi.py +75 -0
  194. angr/analyses/identifier/functions/based_atoi.py +128 -0
  195. angr/analyses/identifier/functions/fdprintf.py +122 -0
  196. angr/analyses/identifier/functions/free.py +64 -0
  197. angr/analyses/identifier/functions/int2str.py +302 -0
  198. angr/analyses/identifier/functions/malloc.py +113 -0
  199. angr/analyses/identifier/functions/memcmp.py +69 -0
  200. angr/analyses/identifier/functions/memcpy.py +89 -0
  201. angr/analyses/identifier/functions/memset.py +43 -0
  202. angr/analyses/identifier/functions/printf.py +122 -0
  203. angr/analyses/identifier/functions/recv_until.py +315 -0
  204. angr/analyses/identifier/functions/skip_calloc.py +72 -0
  205. angr/analyses/identifier/functions/skip_realloc.py +99 -0
  206. angr/analyses/identifier/functions/skip_recv_n.py +107 -0
  207. angr/analyses/identifier/functions/snprintf.py +114 -0
  208. angr/analyses/identifier/functions/sprintf.py +115 -0
  209. angr/analyses/identifier/functions/strcasecmp.py +32 -0
  210. angr/analyses/identifier/functions/strcmp.py +112 -0
  211. angr/analyses/identifier/functions/strcpy.py +43 -0
  212. angr/analyses/identifier/functions/strlen.py +26 -0
  213. angr/analyses/identifier/functions/strncmp.py +103 -0
  214. angr/analyses/identifier/functions/strncpy.py +65 -0
  215. angr/analyses/identifier/functions/strtol.py +91 -0
  216. angr/analyses/identifier/identify.py +848 -0
  217. angr/analyses/identifier/runner.py +359 -0
  218. angr/analyses/init_finder.py +264 -0
  219. angr/analyses/loop_analysis.py +353 -0
  220. angr/analyses/loopfinder.py +174 -0
  221. angr/analyses/propagator/__init__.py +1 -0
  222. angr/analyses/propagator/engine_ail.py +1560 -0
  223. angr/analyses/propagator/engine_base.py +53 -0
  224. angr/analyses/propagator/engine_vex.py +328 -0
  225. angr/analyses/propagator/outdated_definition_walker.py +158 -0
  226. angr/analyses/propagator/propagator.py +422 -0
  227. angr/analyses/propagator/tmpvar_finder.py +17 -0
  228. angr/analyses/propagator/top_checker_mixin.py +14 -0
  229. angr/analyses/propagator/values.py +116 -0
  230. angr/analyses/propagator/vex_vars.py +67 -0
  231. angr/analyses/proximity_graph.py +452 -0
  232. angr/analyses/reaching_definitions/__init__.py +65 -0
  233. angr/analyses/reaching_definitions/call_trace.py +72 -0
  234. angr/analyses/reaching_definitions/dep_graph.py +392 -0
  235. angr/analyses/reaching_definitions/engine_ail.py +1172 -0
  236. angr/analyses/reaching_definitions/engine_vex.py +1102 -0
  237. angr/analyses/reaching_definitions/external_codeloc.py +0 -0
  238. angr/analyses/reaching_definitions/function_handler.py +603 -0
  239. angr/analyses/reaching_definitions/heap_allocator.py +69 -0
  240. angr/analyses/reaching_definitions/rd_initializer.py +235 -0
  241. angr/analyses/reaching_definitions/rd_state.py +613 -0
  242. angr/analyses/reaching_definitions/reaching_definitions.py +594 -0
  243. angr/analyses/reaching_definitions/subject.py +64 -0
  244. angr/analyses/reassembler.py +2970 -0
  245. angr/analyses/soot_class_hierarchy.py +283 -0
  246. angr/analyses/stack_pointer_tracker.py +832 -0
  247. angr/analyses/static_hooker.py +51 -0
  248. angr/analyses/typehoon/__init__.py +1 -0
  249. angr/analyses/typehoon/dfa.py +108 -0
  250. angr/analyses/typehoon/lifter.py +91 -0
  251. angr/analyses/typehoon/simple_solver.py +1258 -0
  252. angr/analyses/typehoon/translator.py +242 -0
  253. angr/analyses/typehoon/typeconsts.py +294 -0
  254. angr/analyses/typehoon/typehoon.py +239 -0
  255. angr/analyses/typehoon/typevars.py +565 -0
  256. angr/analyses/typehoon/variance.py +10 -0
  257. angr/analyses/variable_recovery/__init__.py +2 -0
  258. angr/analyses/variable_recovery/annotations.py +57 -0
  259. angr/analyses/variable_recovery/engine_ail.py +746 -0
  260. angr/analyses/variable_recovery/engine_base.py +962 -0
  261. angr/analyses/variable_recovery/engine_vex.py +580 -0
  262. angr/analyses/variable_recovery/irsb_scanner.py +131 -0
  263. angr/analyses/variable_recovery/variable_recovery.py +552 -0
  264. angr/analyses/variable_recovery/variable_recovery_base.py +452 -0
  265. angr/analyses/variable_recovery/variable_recovery_fast.py +589 -0
  266. angr/analyses/veritesting.py +635 -0
  267. angr/analyses/vfg.py +1945 -0
  268. angr/analyses/vsa_ddg.py +423 -0
  269. angr/analyses/vtable.py +92 -0
  270. angr/analyses/xrefs.py +263 -0
  271. angr/angrdb/__init__.py +9 -0
  272. angr/angrdb/db.py +208 -0
  273. angr/angrdb/models.py +183 -0
  274. angr/angrdb/serializers/__init__.py +2 -0
  275. angr/angrdb/serializers/cfg_model.py +41 -0
  276. angr/angrdb/serializers/comments.py +59 -0
  277. angr/angrdb/serializers/funcs.py +60 -0
  278. angr/angrdb/serializers/kb.py +110 -0
  279. angr/angrdb/serializers/labels.py +58 -0
  280. angr/angrdb/serializers/loader.py +81 -0
  281. angr/angrdb/serializers/structured_code.py +128 -0
  282. angr/angrdb/serializers/variables.py +58 -0
  283. angr/angrdb/serializers/xrefs.py +48 -0
  284. angr/annocfg.py +320 -0
  285. angr/blade.py +430 -0
  286. angr/block.py +506 -0
  287. angr/callable.py +162 -0
  288. angr/calling_conventions.py +2383 -0
  289. angr/code_location.py +168 -0
  290. angr/codenode.py +140 -0
  291. angr/concretization_strategies/__init__.py +97 -0
  292. angr/concretization_strategies/any.py +15 -0
  293. angr/concretization_strategies/any_named.py +32 -0
  294. angr/concretization_strategies/controlled_data.py +54 -0
  295. angr/concretization_strategies/eval.py +18 -0
  296. angr/concretization_strategies/logging.py +32 -0
  297. angr/concretization_strategies/max.py +24 -0
  298. angr/concretization_strategies/nonzero.py +14 -0
  299. angr/concretization_strategies/nonzero_range.py +20 -0
  300. angr/concretization_strategies/norepeats.py +35 -0
  301. angr/concretization_strategies/norepeats_range.py +35 -0
  302. angr/concretization_strategies/range.py +17 -0
  303. angr/concretization_strategies/signed_add.py +24 -0
  304. angr/concretization_strategies/single.py +12 -0
  305. angr/concretization_strategies/solutions.py +18 -0
  306. angr/concretization_strategies/unlimited_range.py +15 -0
  307. angr/distributed/__init__.py +3 -0
  308. angr/distributed/server.py +198 -0
  309. angr/distributed/worker.py +183 -0
  310. angr/engines/__init__.py +41 -0
  311. angr/engines/concrete.py +178 -0
  312. angr/engines/engine.py +212 -0
  313. angr/engines/failure.py +27 -0
  314. angr/engines/hook.py +67 -0
  315. angr/engines/light/__init__.py +2 -0
  316. angr/engines/light/data.py +715 -0
  317. angr/engines/light/engine.py +1441 -0
  318. angr/engines/pcode/__init__.py +2 -0
  319. angr/engines/pcode/behavior.py +995 -0
  320. angr/engines/pcode/cc.py +123 -0
  321. angr/engines/pcode/emulate.py +446 -0
  322. angr/engines/pcode/engine.py +256 -0
  323. angr/engines/pcode/lifter.py +1423 -0
  324. angr/engines/procedure.py +71 -0
  325. angr/engines/soot/__init__.py +1 -0
  326. angr/engines/soot/engine.py +415 -0
  327. angr/engines/soot/exceptions.py +14 -0
  328. angr/engines/soot/expressions/__init__.py +56 -0
  329. angr/engines/soot/expressions/arrayref.py +21 -0
  330. angr/engines/soot/expressions/base.py +22 -0
  331. angr/engines/soot/expressions/binop.py +27 -0
  332. angr/engines/soot/expressions/cast.py +21 -0
  333. angr/engines/soot/expressions/condition.py +34 -0
  334. angr/engines/soot/expressions/constants.py +45 -0
  335. angr/engines/soot/expressions/instanceOf.py +11 -0
  336. angr/engines/soot/expressions/instancefieldref.py +7 -0
  337. angr/engines/soot/expressions/invoke.py +117 -0
  338. angr/engines/soot/expressions/length.py +7 -0
  339. angr/engines/soot/expressions/local.py +7 -0
  340. angr/engines/soot/expressions/new.py +15 -0
  341. angr/engines/soot/expressions/newArray.py +51 -0
  342. angr/engines/soot/expressions/newMultiArray.py +84 -0
  343. angr/engines/soot/expressions/paramref.py +7 -0
  344. angr/engines/soot/expressions/phi.py +29 -0
  345. angr/engines/soot/expressions/staticfieldref.py +7 -0
  346. angr/engines/soot/expressions/thisref.py +6 -0
  347. angr/engines/soot/expressions/unsupported.py +6 -0
  348. angr/engines/soot/field_dispatcher.py +49 -0
  349. angr/engines/soot/method_dispatcher.py +49 -0
  350. angr/engines/soot/statements/__init__.py +30 -0
  351. angr/engines/soot/statements/assign.py +29 -0
  352. angr/engines/soot/statements/base.py +80 -0
  353. angr/engines/soot/statements/goto.py +11 -0
  354. angr/engines/soot/statements/identity.py +14 -0
  355. angr/engines/soot/statements/if_.py +16 -0
  356. angr/engines/soot/statements/invoke.py +11 -0
  357. angr/engines/soot/statements/return_.py +19 -0
  358. angr/engines/soot/statements/switch.py +38 -0
  359. angr/engines/soot/statements/throw.py +12 -0
  360. angr/engines/soot/values/__init__.py +24 -0
  361. angr/engines/soot/values/arrayref.py +124 -0
  362. angr/engines/soot/values/base.py +4 -0
  363. angr/engines/soot/values/constants.py +17 -0
  364. angr/engines/soot/values/instancefieldref.py +42 -0
  365. angr/engines/soot/values/local.py +17 -0
  366. angr/engines/soot/values/paramref.py +17 -0
  367. angr/engines/soot/values/staticfieldref.py +37 -0
  368. angr/engines/soot/values/strref.py +37 -0
  369. angr/engines/soot/values/thisref.py +148 -0
  370. angr/engines/successors.py +540 -0
  371. angr/engines/syscall.py +53 -0
  372. angr/engines/unicorn.py +483 -0
  373. angr/engines/vex/__init__.py +4 -0
  374. angr/engines/vex/claripy/__init__.py +1 -0
  375. angr/engines/vex/claripy/ccall.py +2097 -0
  376. angr/engines/vex/claripy/datalayer.py +149 -0
  377. angr/engines/vex/claripy/irop.py +1279 -0
  378. angr/engines/vex/heavy/__init__.py +5 -0
  379. angr/engines/vex/heavy/actions.py +237 -0
  380. angr/engines/vex/heavy/concretizers.py +394 -0
  381. angr/engines/vex/heavy/dirty.py +467 -0
  382. angr/engines/vex/heavy/heavy.py +379 -0
  383. angr/engines/vex/heavy/inspect.py +51 -0
  384. angr/engines/vex/heavy/resilience.py +85 -0
  385. angr/engines/vex/heavy/super_fastpath.py +34 -0
  386. angr/engines/vex/lifter.py +424 -0
  387. angr/engines/vex/light/__init__.py +3 -0
  388. angr/engines/vex/light/light.py +555 -0
  389. angr/engines/vex/light/resilience.py +73 -0
  390. angr/engines/vex/light/slicing.py +51 -0
  391. angr/errors.py +604 -0
  392. angr/exploration_techniques/__init__.py +176 -0
  393. angr/exploration_techniques/bucketizer.py +96 -0
  394. angr/exploration_techniques/common.py +56 -0
  395. angr/exploration_techniques/dfs.py +34 -0
  396. angr/exploration_techniques/director.py +523 -0
  397. angr/exploration_techniques/driller_core.py +102 -0
  398. angr/exploration_techniques/explorer.py +146 -0
  399. angr/exploration_techniques/lengthlimiter.py +20 -0
  400. angr/exploration_techniques/local_loop_seer.py +64 -0
  401. angr/exploration_techniques/loop_seer.py +239 -0
  402. angr/exploration_techniques/manual_mergepoint.py +80 -0
  403. angr/exploration_techniques/memory_watcher.py +40 -0
  404. angr/exploration_techniques/oppologist.py +93 -0
  405. angr/exploration_techniques/slicecutor.py +115 -0
  406. angr/exploration_techniques/spiller.py +282 -0
  407. angr/exploration_techniques/spiller_db.py +27 -0
  408. angr/exploration_techniques/stochastic.py +57 -0
  409. angr/exploration_techniques/suggestions.py +156 -0
  410. angr/exploration_techniques/symbion.py +78 -0
  411. angr/exploration_techniques/tech_builder.py +47 -0
  412. angr/exploration_techniques/threading.py +77 -0
  413. angr/exploration_techniques/timeout.py +31 -0
  414. angr/exploration_techniques/tracer.py +1101 -0
  415. angr/exploration_techniques/unique.py +104 -0
  416. angr/exploration_techniques/veritesting.py +36 -0
  417. angr/factory.py +385 -0
  418. angr/flirt/__init__.py +126 -0
  419. angr/flirt/build_sig.py +316 -0
  420. angr/graph_utils.py +0 -0
  421. angr/keyed_region.py +532 -0
  422. angr/knowledge_base/__init__.py +1 -0
  423. angr/knowledge_base/knowledge_base.py +145 -0
  424. angr/knowledge_plugins/__init__.py +18 -0
  425. angr/knowledge_plugins/callsite_prototypes.py +52 -0
  426. angr/knowledge_plugins/cfg/__init__.py +16 -0
  427. angr/knowledge_plugins/cfg/cfg_manager.py +94 -0
  428. angr/knowledge_plugins/cfg/cfg_model.py +1057 -0
  429. angr/knowledge_plugins/cfg/cfg_node.py +541 -0
  430. angr/knowledge_plugins/cfg/indirect_jump.py +67 -0
  431. angr/knowledge_plugins/cfg/memory_data.py +156 -0
  432. angr/knowledge_plugins/comments.py +15 -0
  433. angr/knowledge_plugins/custom_strings.py +37 -0
  434. angr/knowledge_plugins/data.py +21 -0
  435. angr/knowledge_plugins/debug_variables.py +221 -0
  436. angr/knowledge_plugins/functions/__init__.py +2 -0
  437. angr/knowledge_plugins/functions/function.py +1694 -0
  438. angr/knowledge_plugins/functions/function_manager.py +501 -0
  439. angr/knowledge_plugins/functions/function_parser.py +295 -0
  440. angr/knowledge_plugins/functions/soot_function.py +131 -0
  441. angr/knowledge_plugins/indirect_jumps.py +34 -0
  442. angr/knowledge_plugins/key_definitions/__init__.py +16 -0
  443. angr/knowledge_plugins/key_definitions/atoms.py +314 -0
  444. angr/knowledge_plugins/key_definitions/constants.py +23 -0
  445. angr/knowledge_plugins/key_definitions/definition.py +217 -0
  446. angr/knowledge_plugins/key_definitions/environment.py +92 -0
  447. angr/knowledge_plugins/key_definitions/heap_address.py +32 -0
  448. angr/knowledge_plugins/key_definitions/key_definition_manager.py +81 -0
  449. angr/knowledge_plugins/key_definitions/live_definitions.py +1074 -0
  450. angr/knowledge_plugins/key_definitions/liveness.py +170 -0
  451. angr/knowledge_plugins/key_definitions/rd_model.py +176 -0
  452. angr/knowledge_plugins/key_definitions/tag.py +77 -0
  453. angr/knowledge_plugins/key_definitions/undefined.py +67 -0
  454. angr/knowledge_plugins/key_definitions/unknown_size.py +83 -0
  455. angr/knowledge_plugins/key_definitions/uses.py +180 -0
  456. angr/knowledge_plugins/labels.py +109 -0
  457. angr/knowledge_plugins/patches.py +125 -0
  458. angr/knowledge_plugins/plugin.py +23 -0
  459. angr/knowledge_plugins/propagations/__init__.py +2 -0
  460. angr/knowledge_plugins/propagations/prop_value.py +193 -0
  461. angr/knowledge_plugins/propagations/propagation_manager.py +60 -0
  462. angr/knowledge_plugins/propagations/propagation_model.py +74 -0
  463. angr/knowledge_plugins/propagations/states.py +1064 -0
  464. angr/knowledge_plugins/structured_code/__init__.py +1 -0
  465. angr/knowledge_plugins/structured_code/manager.py +59 -0
  466. angr/knowledge_plugins/sync/__init__.py +1 -0
  467. angr/knowledge_plugins/sync/sync_controller.py +329 -0
  468. angr/knowledge_plugins/types.py +87 -0
  469. angr/knowledge_plugins/variables/__init__.py +1 -0
  470. angr/knowledge_plugins/variables/variable_access.py +114 -0
  471. angr/knowledge_plugins/variables/variable_manager.py +1191 -0
  472. angr/knowledge_plugins/xrefs/__init__.py +3 -0
  473. angr/knowledge_plugins/xrefs/xref.py +157 -0
  474. angr/knowledge_plugins/xrefs/xref_manager.py +122 -0
  475. angr/knowledge_plugins/xrefs/xref_types.py +13 -0
  476. angr/lib/angr_native.so +0 -0
  477. angr/misc/__init__.py +8 -0
  478. angr/misc/ansi.py +46 -0
  479. angr/misc/autoimport.py +89 -0
  480. angr/misc/bug_report.py +125 -0
  481. angr/misc/hookset.py +106 -0
  482. angr/misc/import_hooks.py +63 -0
  483. angr/misc/loggers.py +130 -0
  484. angr/misc/picklable_lock.py +45 -0
  485. angr/misc/plugins.py +291 -0
  486. angr/misc/range.py +21 -0
  487. angr/misc/testing.py +23 -0
  488. angr/misc/ux.py +31 -0
  489. angr/misc/weakpatch.py +58 -0
  490. angr/procedures/__init__.py +2 -0
  491. angr/procedures/advapi32/__init__.py +0 -0
  492. angr/procedures/cgc/__init__.py +3 -0
  493. angr/procedures/cgc/_terminate.py +10 -0
  494. angr/procedures/cgc/allocate.py +76 -0
  495. angr/procedures/cgc/deallocate.py +59 -0
  496. angr/procedures/cgc/fdwait.py +62 -0
  497. angr/procedures/cgc/random.py +60 -0
  498. angr/procedures/cgc/receive.py +91 -0
  499. angr/procedures/cgc/transmit.py +63 -0
  500. angr/procedures/definitions/__init__.py +784 -0
  501. angr/procedures/definitions/cgc.py +19 -0
  502. angr/procedures/definitions/glibc.py +8384 -0
  503. angr/procedures/definitions/gnulib.py +35 -0
  504. angr/procedures/definitions/libstdcpp.py +20 -0
  505. angr/procedures/definitions/linux_kernel.py +6167 -0
  506. angr/procedures/definitions/linux_loader.py +6 -0
  507. angr/procedures/definitions/msvcr.py +15 -0
  508. angr/procedures/definitions/parse_syscalls_from_local_system.py +49 -0
  509. angr/procedures/definitions/parse_win32json.py +2556 -0
  510. angr/procedures/definitions/types_win32.py +34481 -0
  511. angr/procedures/definitions/wdk_api-ms-win-dx-d3dkmt-l1-1-4.py +44 -0
  512. angr/procedures/definitions/wdk_api-ms-win-dx-d3dkmt-l1-1-6.py +40 -0
  513. angr/procedures/definitions/wdk_clfs.py +154 -0
  514. angr/procedures/definitions/wdk_fltmgr.py +570 -0
  515. angr/procedures/definitions/wdk_fwpkclnt.py +44 -0
  516. angr/procedures/definitions/wdk_fwpuclnt.py +330 -0
  517. angr/procedures/definitions/wdk_gdi32.py +380 -0
  518. angr/procedures/definitions/wdk_hal.py +92 -0
  519. angr/procedures/definitions/wdk_ksecdd.py +76 -0
  520. angr/procedures/definitions/wdk_ndis.py +252 -0
  521. angr/procedures/definitions/wdk_ntoskrnl.py +3463 -0
  522. angr/procedures/definitions/wdk_offreg.py +86 -0
  523. angr/procedures/definitions/wdk_pshed.py +50 -0
  524. angr/procedures/definitions/wdk_secur32.py +54 -0
  525. angr/procedures/definitions/wdk_vhfum.py +48 -0
  526. angr/procedures/definitions/win32_aclui.py +44 -0
  527. angr/procedures/definitions/win32_activeds.py +82 -0
  528. angr/procedures/definitions/win32_advapi32.py +1698 -0
  529. angr/procedures/definitions/win32_advpack.py +138 -0
  530. angr/procedures/definitions/win32_amsi.py +52 -0
  531. angr/procedures/definitions/win32_api-ms-win-appmodel-runtime-l1-1-1.py +58 -0
  532. angr/procedures/definitions/win32_api-ms-win-appmodel-runtime-l1-1-3.py +48 -0
  533. angr/procedures/definitions/win32_api-ms-win-appmodel-runtime-l1-1-6.py +40 -0
  534. angr/procedures/definitions/win32_api-ms-win-core-apiquery-l2-1-0.py +40 -0
  535. angr/procedures/definitions/win32_api-ms-win-core-backgroundtask-l1-1-0.py +40 -0
  536. angr/procedures/definitions/win32_api-ms-win-core-comm-l1-1-1.py +40 -0
  537. angr/procedures/definitions/win32_api-ms-win-core-comm-l1-1-2.py +40 -0
  538. angr/procedures/definitions/win32_api-ms-win-core-enclave-l1-1-1.py +44 -0
  539. angr/procedures/definitions/win32_api-ms-win-core-errorhandling-l1-1-3.py +40 -0
  540. angr/procedures/definitions/win32_api-ms-win-core-featurestaging-l1-1-0.py +48 -0
  541. angr/procedures/definitions/win32_api-ms-win-core-featurestaging-l1-1-1.py +40 -0
  542. angr/procedures/definitions/win32_api-ms-win-core-file-fromapp-l1-1-0.py +60 -0
  543. angr/procedures/definitions/win32_api-ms-win-core-handle-l1-1-0.py +40 -0
  544. angr/procedures/definitions/win32_api-ms-win-core-ioring-l1-1-0.py +62 -0
  545. angr/procedures/definitions/win32_api-ms-win-core-marshal-l1-1-0.py +46 -0
  546. angr/procedures/definitions/win32_api-ms-win-core-memory-l1-1-3.py +46 -0
  547. angr/procedures/definitions/win32_api-ms-win-core-memory-l1-1-4.py +40 -0
  548. angr/procedures/definitions/win32_api-ms-win-core-memory-l1-1-5.py +44 -0
  549. angr/procedures/definitions/win32_api-ms-win-core-memory-l1-1-6.py +46 -0
  550. angr/procedures/definitions/win32_api-ms-win-core-memory-l1-1-7.py +42 -0
  551. angr/procedures/definitions/win32_api-ms-win-core-memory-l1-1-8.py +44 -0
  552. angr/procedures/definitions/win32_api-ms-win-core-path-l1-1-0.py +82 -0
  553. angr/procedures/definitions/win32_api-ms-win-core-psm-appnotify-l1-1-0.py +42 -0
  554. angr/procedures/definitions/win32_api-ms-win-core-psm-appnotify-l1-1-1.py +42 -0
  555. angr/procedures/definitions/win32_api-ms-win-core-realtime-l1-1-1.py +44 -0
  556. angr/procedures/definitions/win32_api-ms-win-core-realtime-l1-1-2.py +44 -0
  557. angr/procedures/definitions/win32_api-ms-win-core-slapi-l1-1-0.py +40 -0
  558. angr/procedures/definitions/win32_api-ms-win-core-state-helpers-l1-1-0.py +40 -0
  559. angr/procedures/definitions/win32_api-ms-win-core-synch-l1-2-0.py +44 -0
  560. angr/procedures/definitions/win32_api-ms-win-core-sysinfo-l1-2-0.py +40 -0
  561. angr/procedures/definitions/win32_api-ms-win-core-sysinfo-l1-2-3.py +42 -0
  562. angr/procedures/definitions/win32_api-ms-win-core-sysinfo-l1-2-4.py +42 -0
  563. angr/procedures/definitions/win32_api-ms-win-core-sysinfo-l1-2-6.py +40 -0
  564. angr/procedures/definitions/win32_api-ms-win-core-util-l1-1-1.py +42 -0
  565. angr/procedures/definitions/win32_api-ms-win-core-winrt-error-l1-1-0.py +43 -0
  566. angr/procedures/definitions/win32_api-ms-win-core-winrt-error-l1-1-1.py +37 -0
  567. angr/procedures/definitions/win32_api-ms-win-core-winrt-l1-1-0.py +39 -0
  568. angr/procedures/definitions/win32_api-ms-win-core-winrt-registration-l1-1-0.py +23 -0
  569. angr/procedures/definitions/win32_api-ms-win-core-winrt-robuffer-l1-1-0.py +23 -0
  570. angr/procedures/definitions/win32_api-ms-win-core-winrt-roparameterizediid-l1-1-0.py +27 -0
  571. angr/procedures/definitions/win32_api-ms-win-core-winrt-string-l1-1-0.py +75 -0
  572. angr/procedures/definitions/win32_api-ms-win-core-winrt-string-l1-1-1.py +23 -0
  573. angr/procedures/definitions/win32_api-ms-win-core-wow64-l1-1-1.py +44 -0
  574. angr/procedures/definitions/win32_api-ms-win-devices-query-l1-1-0.py +56 -0
  575. angr/procedures/definitions/win32_api-ms-win-devices-query-l1-1-1.py +48 -0
  576. angr/procedures/definitions/win32_api-ms-win-dx-d3dkmt-l1-1-0.py +40 -0
  577. angr/procedures/definitions/win32_api-ms-win-gaming-deviceinformation-l1-1-0.py +40 -0
  578. angr/procedures/definitions/win32_api-ms-win-gaming-expandedresources-l1-1-0.py +44 -0
  579. angr/procedures/definitions/win32_api-ms-win-gaming-tcui-l1-1-0.py +52 -0
  580. angr/procedures/definitions/win32_api-ms-win-gaming-tcui-l1-1-1.py +42 -0
  581. angr/procedures/definitions/win32_api-ms-win-gaming-tcui-l1-1-2.py +52 -0
  582. angr/procedures/definitions/win32_api-ms-win-gaming-tcui-l1-1-3.py +42 -0
  583. angr/procedures/definitions/win32_api-ms-win-gaming-tcui-l1-1-4.py +54 -0
  584. angr/procedures/definitions/win32_api-ms-win-mm-misc-l1-1-1.py +40 -0
  585. angr/procedures/definitions/win32_api-ms-win-net-isolation-l1-1-0.py +54 -0
  586. angr/procedures/definitions/win32_api-ms-win-security-base-l1-2-2.py +40 -0
  587. angr/procedures/definitions/win32_api-ms-win-security-isolatedcontainer-l1-1-0.py +40 -0
  588. angr/procedures/definitions/win32_api-ms-win-security-isolatedcontainer-l1-1-1.py +40 -0
  589. angr/procedures/definitions/win32_api-ms-win-service-core-l1-1-3.py +40 -0
  590. angr/procedures/definitions/win32_api-ms-win-service-core-l1-1-4.py +40 -0
  591. angr/procedures/definitions/win32_api-ms-win-service-core-l1-1-5.py +42 -0
  592. angr/procedures/definitions/win32_api-ms-win-shcore-scaling-l1-1-0.py +44 -0
  593. angr/procedures/definitions/win32_api-ms-win-shcore-scaling-l1-1-1.py +50 -0
  594. angr/procedures/definitions/win32_api-ms-win-shcore-scaling-l1-1-2.py +40 -0
  595. angr/procedures/definitions/win32_api-ms-win-shcore-stream-winrt-l1-1-0.py +27 -0
  596. angr/procedures/definitions/win32_api-ms-win-wsl-api-l1-1-0.py +52 -0
  597. angr/procedures/definitions/win32_apphelp.py +40 -0
  598. angr/procedures/definitions/win32_authz.py +104 -0
  599. angr/procedures/definitions/win32_avicap32.py +46 -0
  600. angr/procedures/definitions/win32_avifil32.py +158 -0
  601. angr/procedures/definitions/win32_avrt.py +66 -0
  602. angr/procedures/definitions/win32_bcp47mrm.py +42 -0
  603. angr/procedures/definitions/win32_bcrypt.py +144 -0
  604. angr/procedures/definitions/win32_bcryptprimitives.py +42 -0
  605. angr/procedures/definitions/win32_bluetoothapis.py +120 -0
  606. angr/procedures/definitions/win32_bthprops.py +33 -0
  607. angr/procedures/definitions/win32_bthprops_cpl.py +50 -0
  608. angr/procedures/definitions/win32_cabinet.py +82 -0
  609. angr/procedures/definitions/win32_certadm.py +74 -0
  610. angr/procedures/definitions/win32_certpoleng.py +54 -0
  611. angr/procedures/definitions/win32_cfgmgr32.py +516 -0
  612. angr/procedures/definitions/win32_chakra.py +212 -0
  613. angr/procedures/definitions/win32_cldapi.py +110 -0
  614. angr/procedures/definitions/win32_clfsw32.py +156 -0
  615. angr/procedures/definitions/win32_clusapi.py +598 -0
  616. angr/procedures/definitions/win32_comctl32.py +268 -0
  617. angr/procedures/definitions/win32_comdlg32.py +80 -0
  618. angr/procedures/definitions/win32_compstui.py +46 -0
  619. angr/procedures/definitions/win32_computecore.py +146 -0
  620. angr/procedures/definitions/win32_computenetwork.py +124 -0
  621. angr/procedures/definitions/win32_computestorage.py +62 -0
  622. angr/procedures/definitions/win32_comsvcs.py +52 -0
  623. angr/procedures/definitions/win32_coremessaging.py +23 -0
  624. angr/procedures/definitions/win32_credui.py +76 -0
  625. angr/procedures/definitions/win32_crypt32.py +496 -0
  626. angr/procedures/definitions/win32_cryptnet.py +48 -0
  627. angr/procedures/definitions/win32_cryptui.py +58 -0
  628. angr/procedures/definitions/win32_cryptxml.py +76 -0
  629. angr/procedures/definitions/win32_cscapi.py +46 -0
  630. angr/procedures/definitions/win32_d2d1.py +64 -0
  631. angr/procedures/definitions/win32_d3d10.py +92 -0
  632. angr/procedures/definitions/win32_d3d10_1.py +42 -0
  633. angr/procedures/definitions/win32_d3d11.py +44 -0
  634. angr/procedures/definitions/win32_d3d12.py +54 -0
  635. angr/procedures/definitions/win32_d3d9.py +60 -0
  636. angr/procedures/definitions/win32_d3dcompiler_47.py +90 -0
  637. angr/procedures/definitions/win32_d3dcsx.py +56 -0
  638. angr/procedures/definitions/win32_davclnt.py +74 -0
  639. angr/procedures/definitions/win32_dbgeng.py +46 -0
  640. angr/procedures/definitions/win32_dbghelp.py +476 -0
  641. angr/procedures/definitions/win32_dbgmodel.py +40 -0
  642. angr/procedures/definitions/win32_dciman32.py +78 -0
  643. angr/procedures/definitions/win32_dcomp.py +62 -0
  644. angr/procedures/definitions/win32_ddraw.py +52 -0
  645. angr/procedures/definitions/win32_deviceaccess.py +40 -0
  646. angr/procedures/definitions/win32_dflayout.py +40 -0
  647. angr/procedures/definitions/win32_dhcpcsvc.py +68 -0
  648. angr/procedures/definitions/win32_dhcpcsvc6.py +50 -0
  649. angr/procedures/definitions/win32_dhcpsapi.py +430 -0
  650. angr/procedures/definitions/win32_diagnosticdataquery.py +108 -0
  651. angr/procedures/definitions/win32_dinput8.py +40 -0
  652. angr/procedures/definitions/win32_directml.py +42 -0
  653. angr/procedures/definitions/win32_dmprocessxmlfiltered.py +40 -0
  654. angr/procedures/definitions/win32_dnsapi.py +166 -0
  655. angr/procedures/definitions/win32_drt.py +70 -0
  656. angr/procedures/definitions/win32_drtprov.py +56 -0
  657. angr/procedures/definitions/win32_drttransport.py +42 -0
  658. angr/procedures/definitions/win32_dsound.py +58 -0
  659. angr/procedures/definitions/win32_dsparse.py +76 -0
  660. angr/procedures/definitions/win32_dsprop.py +52 -0
  661. angr/procedures/definitions/win32_dssec.py +46 -0
  662. angr/procedures/definitions/win32_dsuiext.py +46 -0
  663. angr/procedures/definitions/win32_dwmapi.py +100 -0
  664. angr/procedures/definitions/win32_dwrite.py +40 -0
  665. angr/procedures/definitions/win32_dxcompiler.py +42 -0
  666. angr/procedures/definitions/win32_dxcore.py +40 -0
  667. angr/procedures/definitions/win32_dxgi.py +50 -0
  668. angr/procedures/definitions/win32_dxva2.py +114 -0
  669. angr/procedures/definitions/win32_eappcfg.py +66 -0
  670. angr/procedures/definitions/win32_eappprxy.py +74 -0
  671. angr/procedures/definitions/win32_efswrt.py +42 -0
  672. angr/procedures/definitions/win32_elscore.py +48 -0
  673. angr/procedures/definitions/win32_esent.py +496 -0
  674. angr/procedures/definitions/win32_evr.py +52 -0
  675. angr/procedures/definitions/win32_faultrep.py +46 -0
  676. angr/procedures/definitions/win32_fhsvcctl.py +52 -0
  677. angr/procedures/definitions/win32_firewallapi.py +44 -0
  678. angr/procedures/definitions/win32_fltlib.py +94 -0
  679. angr/procedures/definitions/win32_fontsub.py +42 -0
  680. angr/procedures/definitions/win32_forceinline.py +44 -0
  681. angr/procedures/definitions/win32_fwpuclnt.py +422 -0
  682. angr/procedures/definitions/win32_fxsutility.py +42 -0
  683. angr/procedures/definitions/win32_gdi32.py +900 -0
  684. angr/procedures/definitions/win32_gdiplus.py +1296 -0
  685. angr/procedures/definitions/win32_glu32.py +142 -0
  686. angr/procedures/definitions/win32_gpedit.py +50 -0
  687. angr/procedures/definitions/win32_hhctrl_ocx.py +42 -0
  688. angr/procedures/definitions/win32_hid.py +128 -0
  689. angr/procedures/definitions/win32_hlink.py +94 -0
  690. angr/procedures/definitions/win32_hrtfapo.py +40 -0
  691. angr/procedures/definitions/win32_httpapi.py +124 -0
  692. angr/procedures/definitions/win32_icm32.py +80 -0
  693. angr/procedures/definitions/win32_icmui.py +42 -0
  694. angr/procedures/definitions/win32_icu.py +2088 -0
  695. angr/procedures/definitions/win32_ieframe.py +96 -0
  696. angr/procedures/definitions/win32_imagehlp.py +90 -0
  697. angr/procedures/definitions/win32_imgutil.py +56 -0
  698. angr/procedures/definitions/win32_imm32.py +202 -0
  699. angr/procedures/definitions/win32_infocardapi.py +72 -0
  700. angr/procedures/definitions/win32_inkobjcore.py +92 -0
  701. angr/procedures/definitions/win32_iphlpapi.py +440 -0
  702. angr/procedures/definitions/win32_iscsidsc.py +196 -0
  703. angr/procedures/definitions/win32_isolatedwindowsenvironmentutils.py +42 -0
  704. angr/procedures/definitions/win32_kernel32.py +3199 -0
  705. angr/procedures/definitions/win32_kernelbase.py +50 -0
  706. angr/procedures/definitions/win32_keycredmgr.py +46 -0
  707. angr/procedures/definitions/win32_ksproxy_ax.py +50 -0
  708. angr/procedures/definitions/win32_ksuser.py +54 -0
  709. angr/procedures/definitions/win32_ktmw32.py +116 -0
  710. angr/procedures/definitions/win32_licenseprotection.py +42 -0
  711. angr/procedures/definitions/win32_loadperf.py +62 -0
  712. angr/procedures/definitions/win32_magnification.py +76 -0
  713. angr/procedures/definitions/win32_mapi32.py +170 -0
  714. angr/procedures/definitions/win32_mdmlocalmanagement.py +44 -0
  715. angr/procedures/definitions/win32_mdmregistration.py +68 -0
  716. angr/procedures/definitions/win32_mf.py +162 -0
  717. angr/procedures/definitions/win32_mfcore.py +42 -0
  718. angr/procedures/definitions/win32_mfplat.py +328 -0
  719. angr/procedures/definitions/win32_mfplay.py +40 -0
  720. angr/procedures/definitions/win32_mfreadwrite.py +48 -0
  721. angr/procedures/definitions/win32_mfsensorgroup.py +58 -0
  722. angr/procedures/definitions/win32_mfsrcsnk.py +42 -0
  723. angr/procedures/definitions/win32_mgmtapi.py +56 -0
  724. angr/procedures/definitions/win32_mi.py +40 -0
  725. angr/procedures/definitions/win32_mmdevapi.py +40 -0
  726. angr/procedures/definitions/win32_mpr.py +132 -0
  727. angr/procedures/definitions/win32_mprapi.py +262 -0
  728. angr/procedures/definitions/win32_mqrt.py +106 -0
  729. angr/procedures/definitions/win32_mrmsupport.py +92 -0
  730. angr/procedures/definitions/win32_msacm32.py +122 -0
  731. angr/procedures/definitions/win32_msajapi.py +1132 -0
  732. angr/procedures/definitions/win32_mscms.py +196 -0
  733. angr/procedures/definitions/win32_mscoree.py +92 -0
  734. angr/procedures/definitions/win32_msctfmonitor.py +44 -0
  735. angr/procedures/definitions/win32_msdelta.py +70 -0
  736. angr/procedures/definitions/win32_msdmo.py +60 -0
  737. angr/procedures/definitions/win32_msdrm.py +206 -0
  738. angr/procedures/definitions/win32_msi.py +566 -0
  739. angr/procedures/definitions/win32_msimg32.py +44 -0
  740. angr/procedures/definitions/win32_mspatcha.py +70 -0
  741. angr/procedures/definitions/win32_mspatchc.py +56 -0
  742. angr/procedures/definitions/win32_msports.py +52 -0
  743. angr/procedures/definitions/win32_msrating.py +76 -0
  744. angr/procedures/definitions/win32_mssign32.py +58 -0
  745. angr/procedures/definitions/win32_mstask.py +42 -0
  746. angr/procedures/definitions/win32_msvfw32.py +124 -0
  747. angr/procedures/definitions/win32_mswsock.py +70 -0
  748. angr/procedures/definitions/win32_mtxdm.py +40 -0
  749. angr/procedures/definitions/win32_ncrypt.py +116 -0
  750. angr/procedures/definitions/win32_ndfapi.py +70 -0
  751. angr/procedures/definitions/win32_netapi32.py +450 -0
  752. angr/procedures/definitions/win32_netsh.py +54 -0
  753. angr/procedures/definitions/win32_netshell.py +42 -0
  754. angr/procedures/definitions/win32_newdev.py +60 -0
  755. angr/procedures/definitions/win32_ninput.py +98 -0
  756. angr/procedures/definitions/win32_normaliz.py +42 -0
  757. angr/procedures/definitions/win32_ntdll.py +185 -0
  758. angr/procedures/definitions/win32_ntdllk.py +40 -0
  759. angr/procedures/definitions/win32_ntdsapi.py +200 -0
  760. angr/procedures/definitions/win32_ntlanman.py +58 -0
  761. angr/procedures/definitions/win32_odbc32.py +406 -0
  762. angr/procedures/definitions/win32_odbcbcp.py +92 -0
  763. angr/procedures/definitions/win32_ole32.py +672 -0
  764. angr/procedures/definitions/win32_oleacc.py +72 -0
  765. angr/procedures/definitions/win32_oleaut32.py +848 -0
  766. angr/procedures/definitions/win32_oledlg.py +84 -0
  767. angr/procedures/definitions/win32_ondemandconnroutehelper.py +48 -0
  768. angr/procedures/definitions/win32_opengl32.py +748 -0
  769. angr/procedures/definitions/win32_opmxbox.py +44 -0
  770. angr/procedures/definitions/win32_p2p.py +254 -0
  771. angr/procedures/definitions/win32_p2pgraph.py +112 -0
  772. angr/procedures/definitions/win32_pdh.py +234 -0
  773. angr/procedures/definitions/win32_peerdist.py +94 -0
  774. angr/procedures/definitions/win32_powrprof.py +206 -0
  775. angr/procedures/definitions/win32_prntvpt.py +60 -0
  776. angr/procedures/definitions/win32_projectedfslib.py +76 -0
  777. angr/procedures/definitions/win32_propsys.py +474 -0
  778. angr/procedures/definitions/win32_psapi.py +92 -0
  779. angr/procedures/definitions/win32_quartz.py +42 -0
  780. angr/procedures/definitions/win32_query.py +46 -0
  781. angr/procedures/definitions/win32_qwave.py +60 -0
  782. angr/procedures/definitions/win32_rasapi32.py +206 -0
  783. angr/procedures/definitions/win32_rasdlg.py +50 -0
  784. angr/procedures/definitions/win32_resutils.py +278 -0
  785. angr/procedures/definitions/win32_rometadata.py +23 -0
  786. angr/procedures/definitions/win32_rpcns4.py +160 -0
  787. angr/procedures/definitions/win32_rpcproxy.py +46 -0
  788. angr/procedures/definitions/win32_rpcrt4.py +932 -0
  789. angr/procedures/definitions/win32_rstrtmgr.py +60 -0
  790. angr/procedures/definitions/win32_rtm.py +190 -0
  791. angr/procedures/definitions/win32_rtutils.py +120 -0
  792. angr/procedures/definitions/win32_rtworkq.py +104 -0
  793. angr/procedures/definitions/win32_sas.py +40 -0
  794. angr/procedures/definitions/win32_scarddlg.py +48 -0
  795. angr/procedures/definitions/win32_schannel.py +56 -0
  796. angr/procedures/definitions/win32_sechost.py +42 -0
  797. angr/procedures/definitions/win32_secur32.py +216 -0
  798. angr/procedures/definitions/win32_sensapi.py +44 -0
  799. angr/procedures/definitions/win32_sensorsutilsv2.py +118 -0
  800. angr/procedures/definitions/win32_setupapi.py +706 -0
  801. angr/procedures/definitions/win32_sfc.py +50 -0
  802. angr/procedures/definitions/win32_shdocvw.py +44 -0
  803. angr/procedures/definitions/win32_shell32.py +526 -0
  804. angr/procedures/definitions/win32_shlwapi.py +758 -0
  805. angr/procedures/definitions/win32_slc.py +102 -0
  806. angr/procedures/definitions/win32_slcext.py +46 -0
  807. angr/procedures/definitions/win32_slwga.py +40 -0
  808. angr/procedures/definitions/win32_snmpapi.py +90 -0
  809. angr/procedures/definitions/win32_spoolss.py +90 -0
  810. angr/procedures/definitions/win32_srclient.py +40 -0
  811. angr/procedures/definitions/win32_srpapi.py +60 -0
  812. angr/procedures/definitions/win32_sspicli.py +52 -0
  813. angr/procedures/definitions/win32_sti.py +40 -0
  814. angr/procedures/definitions/win32_t2embed.py +66 -0
  815. angr/procedures/definitions/win32_tapi32.py +536 -0
  816. angr/procedures/definitions/win32_tbs.py +66 -0
  817. angr/procedures/definitions/win32_tdh.py +92 -0
  818. angr/procedures/definitions/win32_tokenbinding.py +58 -0
  819. angr/procedures/definitions/win32_traffic.py +78 -0
  820. angr/procedures/definitions/win32_txfw32.py +56 -0
  821. angr/procedures/definitions/win32_ualapi.py +46 -0
  822. angr/procedures/definitions/win32_uiautomationcore.py +234 -0
  823. angr/procedures/definitions/win32_urlmon.py +192 -0
  824. angr/procedures/definitions/win32_user32.py +1565 -0
  825. angr/procedures/definitions/win32_userenv.py +126 -0
  826. angr/procedures/definitions/win32_usp10.py +118 -0
  827. angr/procedures/definitions/win32_uxtheme.py +192 -0
  828. angr/procedures/definitions/win32_verifier.py +40 -0
  829. angr/procedures/definitions/win32_version.py +66 -0
  830. angr/procedures/definitions/win32_vertdll.py +52 -0
  831. angr/procedures/definitions/win32_virtdisk.py +96 -0
  832. angr/procedures/definitions/win32_vmdevicehost.py +64 -0
  833. angr/procedures/definitions/win32_vmsavedstatedumpprovider.py +124 -0
  834. angr/procedures/definitions/win32_vssapi.py +40 -0
  835. angr/procedures/definitions/win32_wcmapi.py +48 -0
  836. angr/procedures/definitions/win32_wdsbp.py +52 -0
  837. angr/procedures/definitions/win32_wdsclientapi.py +112 -0
  838. angr/procedures/definitions/win32_wdsmc.py +50 -0
  839. angr/procedures/definitions/win32_wdspxe.py +100 -0
  840. angr/procedures/definitions/win32_wdstptc.py +64 -0
  841. angr/procedures/definitions/win32_webauthn.py +64 -0
  842. angr/procedures/definitions/win32_webservices.py +424 -0
  843. angr/procedures/definitions/win32_websocket.py +64 -0
  844. angr/procedures/definitions/win32_wecapi.py +68 -0
  845. angr/procedures/definitions/win32_wer.py +80 -0
  846. angr/procedures/definitions/win32_wevtapi.py +108 -0
  847. angr/procedures/definitions/win32_winbio.py +146 -0
  848. angr/procedures/definitions/win32_windows_ai_machinelearning.py +40 -0
  849. angr/procedures/definitions/win32_windows_data_pdf.py +23 -0
  850. angr/procedures/definitions/win32_windows_media_mediacontrol.py +54 -0
  851. angr/procedures/definitions/win32_windows_networking.py +40 -0
  852. angr/procedures/definitions/win32_windows_ui_xaml.py +42 -0
  853. angr/procedures/definitions/win32_windowscodecs.py +56 -0
  854. angr/procedures/definitions/win32_winfax.py +150 -0
  855. angr/procedures/definitions/win32_winhttp.py +150 -0
  856. angr/procedures/definitions/win32_winhvemulation.py +46 -0
  857. angr/procedures/definitions/win32_winhvplatform.py +170 -0
  858. angr/procedures/definitions/win32_wininet.py +630 -0
  859. angr/procedures/definitions/win32_winml.py +40 -0
  860. angr/procedures/definitions/win32_winmm.py +390 -0
  861. angr/procedures/definitions/win32_winscard.py +178 -0
  862. angr/procedures/definitions/win32_winspool.py +363 -0
  863. angr/procedures/definitions/win32_winspool_drv.py +382 -0
  864. angr/procedures/definitions/win32_wintrust.py +158 -0
  865. angr/procedures/definitions/win32_winusb.py +106 -0
  866. angr/procedures/definitions/win32_wlanapi.py +158 -0
  867. angr/procedures/definitions/win32_wlanui.py +40 -0
  868. angr/procedures/definitions/win32_wldap32.py +524 -0
  869. angr/procedures/definitions/win32_wldp.py +56 -0
  870. angr/procedures/definitions/win32_wmvcore.py +60 -0
  871. angr/procedures/definitions/win32_wnvapi.py +42 -0
  872. angr/procedures/definitions/win32_wofutil.py +60 -0
  873. angr/procedures/definitions/win32_ws2_32.py +358 -0
  874. angr/procedures/definitions/win32_wscapi.py +50 -0
  875. angr/procedures/definitions/win32_wsclient.py +44 -0
  876. angr/procedures/definitions/win32_wsdapi.py +102 -0
  877. angr/procedures/definitions/win32_wsmsvc.py +104 -0
  878. angr/procedures/definitions/win32_wsnmp32.py +136 -0
  879. angr/procedures/definitions/win32_wtsapi32.py +164 -0
  880. angr/procedures/definitions/win32_xaudio2_8.py +46 -0
  881. angr/procedures/definitions/win32_xinput1_4.py +52 -0
  882. angr/procedures/definitions/win32_xinputuap.py +35 -0
  883. angr/procedures/definitions/win32_xmllite.py +50 -0
  884. angr/procedures/definitions/win32_xolehlp.py +46 -0
  885. angr/procedures/definitions/win32_xpsprint.py +42 -0
  886. angr/procedures/glibc/__ctype_b_loc.py +22 -0
  887. angr/procedures/glibc/__ctype_tolower_loc.py +22 -0
  888. angr/procedures/glibc/__ctype_toupper_loc.py +22 -0
  889. angr/procedures/glibc/__errno_location.py +6 -0
  890. angr/procedures/glibc/__init__.py +3 -0
  891. angr/procedures/glibc/__libc_init.py +36 -0
  892. angr/procedures/glibc/__libc_start_main.py +294 -0
  893. angr/procedures/glibc/dynamic_loading.py +19 -0
  894. angr/procedures/glibc/scanf.py +10 -0
  895. angr/procedures/glibc/sscanf.py +5 -0
  896. angr/procedures/gnulib/__init__.py +3 -0
  897. angr/procedures/gnulib/xalloc_die.py +13 -0
  898. angr/procedures/gnulib/xstrtol_fatal.py +13 -0
  899. angr/procedures/java/__init__.py +38 -0
  900. angr/procedures/java/unconstrained.py +64 -0
  901. angr/procedures/java_io/__init__.py +0 -0
  902. angr/procedures/java_io/read.py +11 -0
  903. angr/procedures/java_io/write.py +16 -0
  904. angr/procedures/java_jni/__init__.py +475 -0
  905. angr/procedures/java_jni/array_operations.py +309 -0
  906. angr/procedures/java_jni/class_and_interface_operations.py +31 -0
  907. angr/procedures/java_jni/field_access.py +176 -0
  908. angr/procedures/java_jni/global_and_local_refs.py +56 -0
  909. angr/procedures/java_jni/method_calls.py +364 -0
  910. angr/procedures/java_jni/not_implemented.py +25 -0
  911. angr/procedures/java_jni/object_operations.py +95 -0
  912. angr/procedures/java_jni/string_operations.py +86 -0
  913. angr/procedures/java_jni/version_information.py +11 -0
  914. angr/procedures/java_lang/__init__.py +0 -0
  915. angr/procedures/java_lang/character.py +31 -0
  916. angr/procedures/java_lang/double.py +24 -0
  917. angr/procedures/java_lang/exit.py +12 -0
  918. angr/procedures/java_lang/getsimplename.py +15 -0
  919. angr/procedures/java_lang/integer.py +42 -0
  920. angr/procedures/java_lang/load_library.py +8 -0
  921. angr/procedures/java_lang/math.py +14 -0
  922. angr/procedures/java_lang/string.py +78 -0
  923. angr/procedures/java_lang/stringbuilder.py +43 -0
  924. angr/procedures/java_lang/system.py +17 -0
  925. angr/procedures/java_util/__init__.py +0 -0
  926. angr/procedures/java_util/collection.py +34 -0
  927. angr/procedures/java_util/iterator.py +45 -0
  928. angr/procedures/java_util/list.py +98 -0
  929. angr/procedures/java_util/map.py +132 -0
  930. angr/procedures/java_util/random.py +11 -0
  931. angr/procedures/java_util/scanner_nextline.py +22 -0
  932. angr/procedures/libc/__init__.py +3 -0
  933. angr/procedures/libc/abort.py +8 -0
  934. angr/procedures/libc/access.py +10 -0
  935. angr/procedures/libc/atoi.py +14 -0
  936. angr/procedures/libc/atol.py +12 -0
  937. angr/procedures/libc/calloc.py +7 -0
  938. angr/procedures/libc/closelog.py +9 -0
  939. angr/procedures/libc/err.py +13 -0
  940. angr/procedures/libc/error.py +55 -0
  941. angr/procedures/libc/exit.py +10 -0
  942. angr/procedures/libc/fclose.py +20 -0
  943. angr/procedures/libc/feof.py +19 -0
  944. angr/procedures/libc/fflush.py +15 -0
  945. angr/procedures/libc/fgetc.py +24 -0
  946. angr/procedures/libc/fgets.py +68 -0
  947. angr/procedures/libc/fopen.py +64 -0
  948. angr/procedures/libc/fprintf.py +24 -0
  949. angr/procedures/libc/fputc.py +22 -0
  950. angr/procedures/libc/fputs.py +23 -0
  951. angr/procedures/libc/fread.py +22 -0
  952. angr/procedures/libc/free.py +8 -0
  953. angr/procedures/libc/fscanf.py +20 -0
  954. angr/procedures/libc/fseek.py +32 -0
  955. angr/procedures/libc/ftell.py +21 -0
  956. angr/procedures/libc/fwrite.py +18 -0
  957. angr/procedures/libc/getchar.py +13 -0
  958. angr/procedures/libc/getdelim.py +96 -0
  959. angr/procedures/libc/getegid.py +7 -0
  960. angr/procedures/libc/geteuid.py +7 -0
  961. angr/procedures/libc/getgid.py +7 -0
  962. angr/procedures/libc/gets.py +66 -0
  963. angr/procedures/libc/getuid.py +7 -0
  964. angr/procedures/libc/malloc.py +11 -0
  965. angr/procedures/libc/memcmp.py +69 -0
  966. angr/procedures/libc/memcpy.py +37 -0
  967. angr/procedures/libc/memset.py +69 -0
  968. angr/procedures/libc/openlog.py +9 -0
  969. angr/procedures/libc/perror.py +12 -0
  970. angr/procedures/libc/printf.py +33 -0
  971. angr/procedures/libc/putchar.py +12 -0
  972. angr/procedures/libc/puts.py +16 -0
  973. angr/procedures/libc/rand.py +7 -0
  974. angr/procedures/libc/realloc.py +7 -0
  975. angr/procedures/libc/rewind.py +11 -0
  976. angr/procedures/libc/scanf.py +20 -0
  977. angr/procedures/libc/setbuf.py +8 -0
  978. angr/procedures/libc/setvbuf.py +6 -0
  979. angr/procedures/libc/snprintf.py +33 -0
  980. angr/procedures/libc/sprintf.py +22 -0
  981. angr/procedures/libc/srand.py +6 -0
  982. angr/procedures/libc/sscanf.py +13 -0
  983. angr/procedures/libc/stpcpy.py +18 -0
  984. angr/procedures/libc/strcat.py +13 -0
  985. angr/procedures/libc/strchr.py +44 -0
  986. angr/procedures/libc/strcmp.py +28 -0
  987. angr/procedures/libc/strcpy.py +13 -0
  988. angr/procedures/libc/strlen.py +99 -0
  989. angr/procedures/libc/strncat.py +18 -0
  990. angr/procedures/libc/strncmp.py +180 -0
  991. angr/procedures/libc/strncpy.py +18 -0
  992. angr/procedures/libc/strnlen.py +13 -0
  993. angr/procedures/libc/strstr.py +94 -0
  994. angr/procedures/libc/strtol.py +263 -0
  995. angr/procedures/libc/strtoul.py +9 -0
  996. angr/procedures/libc/system.py +12 -0
  997. angr/procedures/libc/time.py +9 -0
  998. angr/procedures/libc/tmpnam.py +19 -0
  999. angr/procedures/libc/tolower.py +7 -0
  1000. angr/procedures/libc/toupper.py +7 -0
  1001. angr/procedures/libc/ungetc.py +19 -0
  1002. angr/procedures/libc/vsnprintf.py +16 -0
  1003. angr/procedures/libc/wchar.py +15 -0
  1004. angr/procedures/libstdcpp/__init__.py +0 -0
  1005. angr/procedures/libstdcpp/_unwind_resume.py +10 -0
  1006. angr/procedures/libstdcpp/std____throw_bad_alloc.py +12 -0
  1007. angr/procedures/libstdcpp/std____throw_bad_cast.py +12 -0
  1008. angr/procedures/libstdcpp/std____throw_length_error.py +12 -0
  1009. angr/procedures/libstdcpp/std____throw_logic_error.py +12 -0
  1010. angr/procedures/libstdcpp/std__terminate.py +12 -0
  1011. angr/procedures/linux_kernel/__init__.py +3 -0
  1012. angr/procedures/linux_kernel/access.py +17 -0
  1013. angr/procedures/linux_kernel/arch_prctl.py +33 -0
  1014. angr/procedures/linux_kernel/arm_user_helpers.py +58 -0
  1015. angr/procedures/linux_kernel/brk.py +17 -0
  1016. angr/procedures/linux_kernel/cwd.py +27 -0
  1017. angr/procedures/linux_kernel/fstat.py +137 -0
  1018. angr/procedures/linux_kernel/fstat64.py +169 -0
  1019. angr/procedures/linux_kernel/futex.py +17 -0
  1020. angr/procedures/linux_kernel/getegid.py +16 -0
  1021. angr/procedures/linux_kernel/geteuid.py +16 -0
  1022. angr/procedures/linux_kernel/getgid.py +16 -0
  1023. angr/procedures/linux_kernel/getpid.py +13 -0
  1024. angr/procedures/linux_kernel/getrlimit.py +24 -0
  1025. angr/procedures/linux_kernel/gettid.py +8 -0
  1026. angr/procedures/linux_kernel/getuid.py +16 -0
  1027. angr/procedures/linux_kernel/iovec.py +43 -0
  1028. angr/procedures/linux_kernel/lseek.py +39 -0
  1029. angr/procedures/linux_kernel/mmap.py +15 -0
  1030. angr/procedures/linux_kernel/mprotect.py +41 -0
  1031. angr/procedures/linux_kernel/munmap.py +7 -0
  1032. angr/procedures/linux_kernel/openat.py +28 -0
  1033. angr/procedures/linux_kernel/set_tid_address.py +7 -0
  1034. angr/procedures/linux_kernel/sigaction.py +16 -0
  1035. angr/procedures/linux_kernel/sigprocmask.py +20 -0
  1036. angr/procedures/linux_kernel/stat.py +22 -0
  1037. angr/procedures/linux_kernel/sysinfo.py +58 -0
  1038. angr/procedures/linux_kernel/tgkill.py +7 -0
  1039. angr/procedures/linux_kernel/time.py +30 -0
  1040. angr/procedures/linux_kernel/uid.py +29 -0
  1041. angr/procedures/linux_kernel/uname.py +28 -0
  1042. angr/procedures/linux_kernel/unlink.py +22 -0
  1043. angr/procedures/linux_kernel/vsyscall.py +15 -0
  1044. angr/procedures/linux_loader/__init__.py +3 -0
  1045. angr/procedures/linux_loader/_dl_initial_error_catch_tsd.py +6 -0
  1046. angr/procedures/linux_loader/_dl_rtld_lock.py +14 -0
  1047. angr/procedures/linux_loader/sim_loader.py +53 -0
  1048. angr/procedures/linux_loader/tls.py +40 -0
  1049. angr/procedures/msvcr/__getmainargs.py +15 -0
  1050. angr/procedures/msvcr/__init__.py +4 -0
  1051. angr/procedures/msvcr/_initterm.py +37 -0
  1052. angr/procedures/msvcr/fmode.py +28 -0
  1053. angr/procedures/ntdll/__init__.py +0 -0
  1054. angr/procedures/ntdll/exceptions.py +57 -0
  1055. angr/procedures/posix/__init__.py +3 -0
  1056. angr/procedures/posix/accept.py +29 -0
  1057. angr/procedures/posix/bind.py +12 -0
  1058. angr/procedures/posix/bzero.py +6 -0
  1059. angr/procedures/posix/chroot.py +26 -0
  1060. angr/procedures/posix/close.py +9 -0
  1061. angr/procedures/posix/closedir.py +6 -0
  1062. angr/procedures/posix/dup.py +55 -0
  1063. angr/procedures/posix/fcntl.py +9 -0
  1064. angr/procedures/posix/fdopen.py +77 -0
  1065. angr/procedures/posix/fileno.py +17 -0
  1066. angr/procedures/posix/fork.py +10 -0
  1067. angr/procedures/posix/getenv.py +34 -0
  1068. angr/procedures/posix/gethostbyname.py +42 -0
  1069. angr/procedures/posix/getpass.py +18 -0
  1070. angr/procedures/posix/getsockopt.py +10 -0
  1071. angr/procedures/posix/htonl.py +11 -0
  1072. angr/procedures/posix/htons.py +11 -0
  1073. angr/procedures/posix/inet_ntoa.py +61 -0
  1074. angr/procedures/posix/listen.py +12 -0
  1075. angr/procedures/posix/mmap.py +140 -0
  1076. angr/procedures/posix/open.py +17 -0
  1077. angr/procedures/posix/opendir.py +9 -0
  1078. angr/procedures/posix/poll.py +54 -0
  1079. angr/procedures/posix/pread64.py +45 -0
  1080. angr/procedures/posix/pthread.py +87 -0
  1081. angr/procedures/posix/pwrite64.py +45 -0
  1082. angr/procedures/posix/read.py +12 -0
  1083. angr/procedures/posix/readdir.py +59 -0
  1084. angr/procedures/posix/recv.py +12 -0
  1085. angr/procedures/posix/recvfrom.py +12 -0
  1086. angr/procedures/posix/select.py +46 -0
  1087. angr/procedures/posix/send.py +22 -0
  1088. angr/procedures/posix/setsockopt.py +8 -0
  1089. angr/procedures/posix/sigaction.py +20 -0
  1090. angr/procedures/posix/sim_time.py +45 -0
  1091. angr/procedures/posix/sleep.py +7 -0
  1092. angr/procedures/posix/socket.py +18 -0
  1093. angr/procedures/posix/strcasecmp.py +23 -0
  1094. angr/procedures/posix/strdup.py +17 -0
  1095. angr/procedures/posix/strtok_r.py +65 -0
  1096. angr/procedures/posix/syslog.py +15 -0
  1097. angr/procedures/posix/tz.py +8 -0
  1098. angr/procedures/posix/unlink.py +10 -0
  1099. angr/procedures/posix/usleep.py +7 -0
  1100. angr/procedures/posix/write.py +12 -0
  1101. angr/procedures/procedure_dict.py +48 -0
  1102. angr/procedures/stubs/CallReturn.py +12 -0
  1103. angr/procedures/stubs/NoReturnUnconstrained.py +12 -0
  1104. angr/procedures/stubs/Nop.py +6 -0
  1105. angr/procedures/stubs/PathTerminator.py +8 -0
  1106. angr/procedures/stubs/Redirect.py +15 -0
  1107. angr/procedures/stubs/ReturnChar.py +10 -0
  1108. angr/procedures/stubs/ReturnUnconstrained.py +24 -0
  1109. angr/procedures/stubs/UnresolvableCallTarget.py +8 -0
  1110. angr/procedures/stubs/UnresolvableJumpTarget.py +8 -0
  1111. angr/procedures/stubs/UserHook.py +15 -0
  1112. angr/procedures/stubs/__init__.py +3 -0
  1113. angr/procedures/stubs/b64_decode.py +12 -0
  1114. angr/procedures/stubs/caller.py +13 -0
  1115. angr/procedures/stubs/crazy_scanf.py +17 -0
  1116. angr/procedures/stubs/format_parser.py +677 -0
  1117. angr/procedures/stubs/syscall_stub.py +26 -0
  1118. angr/procedures/testing/__init__.py +3 -0
  1119. angr/procedures/testing/manyargs.py +8 -0
  1120. angr/procedures/testing/retreg.py +8 -0
  1121. angr/procedures/tracer/__init__.py +4 -0
  1122. angr/procedures/tracer/random.py +8 -0
  1123. angr/procedures/tracer/receive.py +21 -0
  1124. angr/procedures/tracer/transmit.py +24 -0
  1125. angr/procedures/uclibc/__init__.py +3 -0
  1126. angr/procedures/uclibc/__uClibc_main.py +9 -0
  1127. angr/procedures/win32/EncodePointer.py +6 -0
  1128. angr/procedures/win32/ExitProcess.py +8 -0
  1129. angr/procedures/win32/GetCommandLine.py +11 -0
  1130. angr/procedures/win32/GetCurrentProcessId.py +6 -0
  1131. angr/procedures/win32/GetCurrentThreadId.py +6 -0
  1132. angr/procedures/win32/GetLastInputInfo.py +37 -0
  1133. angr/procedures/win32/GetModuleHandle.py +30 -0
  1134. angr/procedures/win32/GetProcessAffinityMask.py +34 -0
  1135. angr/procedures/win32/InterlockedExchange.py +14 -0
  1136. angr/procedures/win32/IsProcessorFeaturePresent.py +6 -0
  1137. angr/procedures/win32/VirtualAlloc.py +113 -0
  1138. angr/procedures/win32/VirtualProtect.py +59 -0
  1139. angr/procedures/win32/__init__.py +3 -0
  1140. angr/procedures/win32/critical_section.py +11 -0
  1141. angr/procedures/win32/dynamic_loading.py +103 -0
  1142. angr/procedures/win32/file_handles.py +47 -0
  1143. angr/procedures/win32/gethostbyname.py +10 -0
  1144. angr/procedures/win32/heap.py +42 -0
  1145. angr/procedures/win32/is_bad_ptr.py +25 -0
  1146. angr/procedures/win32/local_storage.py +85 -0
  1147. angr/procedures/win32/mutex.py +10 -0
  1148. angr/procedures/win32/sim_time.py +135 -0
  1149. angr/procedures/win32/system_paths.py +34 -0
  1150. angr/procedures/win32_kernel/ExAllocatePool.py +12 -0
  1151. angr/procedures/win32_kernel/ExFreePoolWithTag.py +7 -0
  1152. angr/procedures/win32_kernel/__init__.py +3 -0
  1153. angr/procedures/win_user32/__init__.py +0 -0
  1154. angr/procedures/win_user32/chars.py +12 -0
  1155. angr/procedures/win_user32/keyboard.py +13 -0
  1156. angr/procedures/win_user32/messagebox.py +49 -0
  1157. angr/project.py +834 -0
  1158. angr/protos/__init__.py +13 -0
  1159. angr/protos/cfg_pb2.py +31 -0
  1160. angr/protos/function_pb2.py +37 -0
  1161. angr/protos/primitives_pb2.py +124 -0
  1162. angr/protos/variables_pb2.py +126 -0
  1163. angr/protos/xrefs_pb2.py +34 -0
  1164. angr/py.typed +1 -0
  1165. angr/serializable.py +63 -0
  1166. angr/service.py +35 -0
  1167. angr/sim_manager.py +971 -0
  1168. angr/sim_options.py +444 -0
  1169. angr/sim_procedure.py +606 -0
  1170. angr/sim_state.py +1003 -0
  1171. angr/sim_state_options.py +409 -0
  1172. angr/sim_type.py +3372 -0
  1173. angr/sim_variable.py +562 -0
  1174. angr/simos/__init__.py +31 -0
  1175. angr/simos/cgc.py +152 -0
  1176. angr/simos/javavm.py +471 -0
  1177. angr/simos/linux.py +519 -0
  1178. angr/simos/simos.py +450 -0
  1179. angr/simos/snimmuc_nxp.py +152 -0
  1180. angr/simos/userland.py +163 -0
  1181. angr/simos/windows.py +562 -0
  1182. angr/slicer.py +353 -0
  1183. angr/state_hierarchy.py +262 -0
  1184. angr/state_plugins/__init__.py +29 -0
  1185. angr/state_plugins/callstack.py +404 -0
  1186. angr/state_plugins/cgc.py +153 -0
  1187. angr/state_plugins/concrete.py +297 -0
  1188. angr/state_plugins/debug_variables.py +194 -0
  1189. angr/state_plugins/filesystem.py +469 -0
  1190. angr/state_plugins/gdb.py +146 -0
  1191. angr/state_plugins/globals.py +62 -0
  1192. angr/state_plugins/heap/__init__.py +5 -0
  1193. angr/state_plugins/heap/heap_base.py +126 -0
  1194. angr/state_plugins/heap/heap_brk.py +134 -0
  1195. angr/state_plugins/heap/heap_freelist.py +210 -0
  1196. angr/state_plugins/heap/heap_libc.py +45 -0
  1197. angr/state_plugins/heap/heap_ptmalloc.py +646 -0
  1198. angr/state_plugins/heap/utils.py +21 -0
  1199. angr/state_plugins/history.py +548 -0
  1200. angr/state_plugins/inspect.py +376 -0
  1201. angr/state_plugins/javavm_classloader.py +133 -0
  1202. angr/state_plugins/jni_references.py +93 -0
  1203. angr/state_plugins/libc.py +1263 -0
  1204. angr/state_plugins/light_registers.py +170 -0
  1205. angr/state_plugins/log.py +85 -0
  1206. angr/state_plugins/loop_data.py +92 -0
  1207. angr/state_plugins/plugin.py +155 -0
  1208. angr/state_plugins/posix.py +709 -0
  1209. angr/state_plugins/preconstrainer.py +195 -0
  1210. angr/state_plugins/scratch.py +175 -0
  1211. angr/state_plugins/sim_action.py +334 -0
  1212. angr/state_plugins/sim_action_object.py +148 -0
  1213. angr/state_plugins/sim_event.py +58 -0
  1214. angr/state_plugins/solver.py +1129 -0
  1215. angr/state_plugins/symbolizer.py +292 -0
  1216. angr/state_plugins/trace_additions.py +752 -0
  1217. angr/state_plugins/uc_manager.py +85 -0
  1218. angr/state_plugins/unicorn_engine.py +1899 -0
  1219. angr/state_plugins/view.py +341 -0
  1220. angr/storage/__init__.py +9 -0
  1221. angr/storage/file.py +1219 -0
  1222. angr/storage/memory_mixins/__init__.py +393 -0
  1223. angr/storage/memory_mixins/__init__.pyi +49 -0
  1224. angr/storage/memory_mixins/actions_mixin.py +69 -0
  1225. angr/storage/memory_mixins/address_concretization_mixin.py +388 -0
  1226. angr/storage/memory_mixins/bvv_conversion_mixin.py +74 -0
  1227. angr/storage/memory_mixins/clouseau_mixin.py +131 -0
  1228. angr/storage/memory_mixins/conditional_store_mixin.py +24 -0
  1229. angr/storage/memory_mixins/convenient_mappings_mixin.py +257 -0
  1230. angr/storage/memory_mixins/default_filler_mixin.py +146 -0
  1231. angr/storage/memory_mixins/dirty_addrs_mixin.py +9 -0
  1232. angr/storage/memory_mixins/hex_dumper_mixin.py +85 -0
  1233. angr/storage/memory_mixins/javavm_memory/__init__.py +1 -0
  1234. angr/storage/memory_mixins/javavm_memory/javavm_memory_mixin.py +394 -0
  1235. angr/storage/memory_mixins/keyvalue_memory/__init__.py +1 -0
  1236. angr/storage/memory_mixins/keyvalue_memory/keyvalue_memory_mixin.py +36 -0
  1237. angr/storage/memory_mixins/label_merger_mixin.py +31 -0
  1238. angr/storage/memory_mixins/multi_value_merger_mixin.py +68 -0
  1239. angr/storage/memory_mixins/name_resolution_mixin.py +70 -0
  1240. angr/storage/memory_mixins/paged_memory/__init__.py +0 -0
  1241. angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +266 -0
  1242. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +750 -0
  1243. angr/storage/memory_mixins/paged_memory/paged_memory_multivalue_mixin.py +63 -0
  1244. angr/storage/memory_mixins/paged_memory/pages/__init__.py +33 -0
  1245. angr/storage/memory_mixins/paged_memory/pages/cooperation.py +330 -0
  1246. angr/storage/memory_mixins/paged_memory/pages/history_tracking_mixin.py +87 -0
  1247. angr/storage/memory_mixins/paged_memory/pages/ispo_mixin.py +53 -0
  1248. angr/storage/memory_mixins/paged_memory/pages/list_page.py +346 -0
  1249. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +290 -0
  1250. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +434 -0
  1251. angr/storage/memory_mixins/paged_memory/pages/permissions_mixin.py +33 -0
  1252. angr/storage/memory_mixins/paged_memory/pages/refcount_mixin.py +51 -0
  1253. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +468 -0
  1254. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +36 -0
  1255. angr/storage/memory_mixins/paged_memory/stack_allocation_mixin.py +73 -0
  1256. angr/storage/memory_mixins/regioned_memory/__init__.py +6 -0
  1257. angr/storage/memory_mixins/regioned_memory/abstract_address_descriptor.py +35 -0
  1258. angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +43 -0
  1259. angr/storage/memory_mixins/regioned_memory/region_category_mixin.py +7 -0
  1260. angr/storage/memory_mixins/regioned_memory/region_data.py +245 -0
  1261. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +125 -0
  1262. angr/storage/memory_mixins/regioned_memory/regioned_address_concretization_mixin.py +118 -0
  1263. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +462 -0
  1264. angr/storage/memory_mixins/regioned_memory/static_find_mixin.py +70 -0
  1265. angr/storage/memory_mixins/simple_interface_mixin.py +73 -0
  1266. angr/storage/memory_mixins/simplification_mixin.py +13 -0
  1267. angr/storage/memory_mixins/size_resolution_mixin.py +140 -0
  1268. angr/storage/memory_mixins/slotted_memory.py +140 -0
  1269. angr/storage/memory_mixins/smart_find_mixin.py +159 -0
  1270. angr/storage/memory_mixins/symbolic_merger_mixin.py +12 -0
  1271. angr/storage/memory_mixins/top_merger_mixin.py +24 -0
  1272. angr/storage/memory_mixins/underconstrained_mixin.py +67 -0
  1273. angr/storage/memory_mixins/unwrapper_mixin.py +26 -0
  1274. angr/storage/memory_object.py +194 -0
  1275. angr/storage/pcap.py +65 -0
  1276. angr/tablespecs.py +90 -0
  1277. angr/utils/__init__.py +33 -0
  1278. angr/utils/algo.py +33 -0
  1279. angr/utils/constants.py +7 -0
  1280. angr/utils/cowdict.py +64 -0
  1281. angr/utils/dynamic_dictlist.py +92 -0
  1282. angr/utils/enums_conv.py +80 -0
  1283. angr/utils/env.py +11 -0
  1284. angr/utils/formatting.py +124 -0
  1285. angr/utils/funcid.py +133 -0
  1286. angr/utils/graph.py +822 -0
  1287. angr/utils/lazy_import.py +12 -0
  1288. angr/utils/library.py +214 -0
  1289. angr/utils/loader.py +55 -0
  1290. angr/utils/mp.py +64 -0
  1291. angr/utils/segment_list.py +558 -0
  1292. angr/utils/timing.py +45 -0
  1293. angr/utils/typing.py +17 -0
  1294. angr/vaults.py +370 -0
  1295. angr-9.2.103.dist-info/LICENSE +24 -0
  1296. angr-9.2.103.dist-info/METADATA +119 -0
  1297. angr-9.2.103.dist-info/RECORD +1300 -0
  1298. angr-9.2.103.dist-info/WHEEL +5 -0
  1299. angr-9.2.103.dist-info/entry_points.txt +2 -0
  1300. angr-9.2.103.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2917 @@
1
+ # pylint:disable=line-too-long,multiple-statements
2
+ from typing import Optional, TYPE_CHECKING, Any
3
+ import logging
4
+ from collections import defaultdict
5
+
6
+ import networkx
7
+ from sortedcontainers import SortedDict
8
+
9
+ import pyvex
10
+ from claripy.utils.orderedset import OrderedSet
11
+ from cle import ELF, PE, Blob, TLSObject, MachO, ExternObject, KernelObject, FunctionHintSource, Hex, Coff, SRec, XBE
12
+ from cle.backends import NamedRegion
13
+ import archinfo
14
+ from archinfo.arch_soot import SootAddressDescriptor
15
+ from archinfo.arch_arm import is_arm_arch, get_real_address_if_arm
16
+
17
+ from angr.knowledge_plugins.functions.function_manager import FunctionManager
18
+ from angr.knowledge_plugins.functions.function import Function
19
+ from angr.knowledge_plugins.cfg import IndirectJump, CFGNode, CFGENode, CFGModel # pylint:disable=unused-import
20
+ from angr.misc.ux import deprecated
21
+ from angr.procedures.stubs.UnresolvableJumpTarget import UnresolvableJumpTarget
22
+ from angr.utils.constants import DEFAULT_STATEMENT
23
+ from angr.procedures.procedure_dict import SIM_PROCEDURES
24
+ from angr.errors import (
25
+ AngrCFGError,
26
+ SimTranslationError,
27
+ SimMemoryError,
28
+ SimIRSBError,
29
+ SimEngineError,
30
+ AngrUnsupportedSyscallError,
31
+ SimError,
32
+ )
33
+ from angr.codenode import HookNode, BlockNode
34
+ from angr.engines.vex.lifter import VEX_IRSB_MAX_SIZE, VEX_IRSB_MAX_INST
35
+ from angr.analyses import Analysis
36
+ from angr.analyses.stack_pointer_tracker import StackPointerTracker
37
+ from .indirect_jump_resolvers.default_resolvers import default_indirect_jump_resolvers
38
+
39
+ if TYPE_CHECKING:
40
+ from angr.sim_state import SimState
41
+
42
+
43
+ l = logging.getLogger(name=__name__)
44
+
45
+
46
+ class CFGBase(Analysis):
47
+ """
48
+ The base class for control flow graphs.
49
+ """
50
+
51
+ tag: str | None = None
52
+ _cle_pseudo_objects = (ExternObject, KernelObject, TLSObject)
53
+
54
+ def __init__(
55
+ self,
56
+ sort,
57
+ context_sensitivity_level,
58
+ normalize=False,
59
+ binary=None,
60
+ objects=None,
61
+ regions=None,
62
+ exclude_sparse_regions=True,
63
+ skip_specific_regions=True,
64
+ force_segment=False,
65
+ base_state=None,
66
+ resolve_indirect_jumps=True,
67
+ indirect_jump_resolvers=None,
68
+ indirect_jump_target_limit=100000,
69
+ detect_tail_calls=False,
70
+ low_priority=False,
71
+ skip_unmapped_addrs=True,
72
+ sp_tracking_track_memory=True,
73
+ model=None,
74
+ ):
75
+ """
76
+ :param str sort: 'fast' or 'emulated'.
77
+ :param int context_sensitivity_level: The level of context-sensitivity of this CFG (see documentation for
78
+ further details). It ranges from 0 to infinity.
79
+ :param bool normalize: Whether the CFG as well as all Function graphs should be normalized.
80
+ :param cle.backends.Backend binary: The binary to recover CFG on. By default, the main binary is used.
81
+ :param objects: A list of objects to recover the CFG on. By default, it will recover
82
+ the CFG of all loaded objects.
83
+ :param iterable regions: A list of tuples in the form of (start address, end address)
84
+ describing memory regions that the CFG should cover.
85
+ :param bool force_segment: Force CFGFast to rely on binary segments instead of sections.
86
+ :param angr.SimState base_state: A state to use as a backer for all memory loads.
87
+ :param bool resolve_indirect_jumps: Whether to try to resolve indirect jumps.
88
+ This is necessary to resolve jump targets from jump tables, etc.
89
+ :param list indirect_jump_resolvers: A custom list of indirect jump resolvers.
90
+ If this list is None or empty, default indirect jump resolvers
91
+ specific to this architecture and binary types will be loaded.
92
+ :param int indirect_jump_target_limit: Maximum indirect jump targets to be recovered.
93
+ :param skip_unmapped_addrs: Ignore all branches into unmapped regions. True by default. You may
94
+ want to set it to False if you are analyzing manually patched
95
+ binaries or malware samples.
96
+ :param bool detect_tail_calls: Aggressive tail-call optimization detection. This option is only
97
+ respected in make_functions().
98
+ :param bool sp_tracking_track_memory: Whether or not to track memory writes if tracking the stack pointer.
99
+ This increases the accuracy of stack pointer tracking,
100
+ especially for architectures without a base pointer.
101
+ Only used if detect_tail_calls is enabled.
102
+ :param None or CFGModel model: The CFGModel instance to write to. A new CFGModel instance will be
103
+ created and registered with the knowledge base if `model` is None.
104
+
105
+ :return: None
106
+ """
107
+
108
+ self.sort = sort
109
+ self._context_sensitivity_level = context_sensitivity_level
110
+
111
+ # Sanity checks
112
+ if context_sensitivity_level < 0:
113
+ raise ValueError("Unsupported context sensitivity level %d" % context_sensitivity_level)
114
+
115
+ self._binary = binary if binary is not None else self.project.loader.main_object
116
+ self._force_segment = force_segment
117
+ self._base_state = base_state
118
+ self._detect_tail_calls = detect_tail_calls
119
+ self._low_priority = low_priority
120
+ self._skip_unmapped_addrs = skip_unmapped_addrs
121
+
122
+ # Initialization
123
+ self._edge_map = None
124
+ self._loop_back_edges = None
125
+ self._overlapped_loop_headers = None
126
+ self._thumb_addrs = set()
127
+ self._tail_calls = set()
128
+
129
+ # Store all the functions analyzed before the set is cleared
130
+ # Used for performance optimization
131
+ self._updated_nonreturning_functions: set[int] | None = None
132
+
133
+ self._normalize = normalize
134
+
135
+ # Flag, whether to track memory writes in stack pointer tracking
136
+ self._sp_tracking_track_memory = sp_tracking_track_memory
137
+
138
+ # IndirectJump object that describe all indirect exits found in the binary
139
+ # stores as a map between addresses and IndirectJump objects
140
+ self.indirect_jumps: dict[int, IndirectJump] = {}
141
+ self._indirect_jumps_to_resolve = set()
142
+
143
+ # Indirect jump resolvers
144
+ self._indirect_jump_target_limit = indirect_jump_target_limit
145
+ self._resolve_indirect_jumps = resolve_indirect_jumps
146
+ self.timeless_indirect_jump_resolvers = []
147
+ self.indirect_jump_resolvers = []
148
+ if not indirect_jump_resolvers:
149
+ indirect_jump_resolvers = default_indirect_jump_resolvers(self._binary, self.project)
150
+ if self._resolve_indirect_jumps and indirect_jump_resolvers:
151
+ # split them into different groups for the sake of speed
152
+ for ijr in indirect_jump_resolvers:
153
+ if ijr.timeless:
154
+ self.timeless_indirect_jump_resolvers.append(ijr)
155
+ else:
156
+ self.indirect_jump_resolvers.append(ijr)
157
+
158
+ l.info(
159
+ "Loaded %d indirect jump resolvers (%d timeless, %d generic).",
160
+ len(self.timeless_indirect_jump_resolvers) + len(self.indirect_jump_resolvers),
161
+ len(self.timeless_indirect_jump_resolvers),
162
+ len(self.indirect_jump_resolvers),
163
+ )
164
+
165
+ # Get all executable memory regions
166
+ self._exec_mem_regions = self._executable_memory_regions(None, self._force_segment)
167
+ self._exec_mem_region_size = sum((end - start) for start, end in self._exec_mem_regions)
168
+
169
+ # initialize UnresolvableJumpTarget and UnresolvableCallTarget SimProcedure
170
+ # but we do not want to hook the same symbol multiple times
171
+ ut_jump_addr = self.project.loader.extern_object.get_pseudo_addr("UnresolvableJumpTarget")
172
+ if not self.project.is_hooked(ut_jump_addr):
173
+ self.project.hook(ut_jump_addr, SIM_PROCEDURES["stubs"]["UnresolvableJumpTarget"]())
174
+ self._unresolvable_jump_target_addr = ut_jump_addr
175
+ ut_call_addr = self.project.loader.extern_object.get_pseudo_addr("UnresolvableCallTarget")
176
+ if not self.project.is_hooked(ut_call_addr):
177
+ self.project.hook(ut_call_addr, SIM_PROCEDURES["stubs"]["UnresolvableCallTarget"]())
178
+ self._unresolvable_call_target_addr = ut_call_addr
179
+
180
+ # partially and fully analyzed functions
181
+ # this is implemented as a state machine: jobs (CFGJob instances) of each function are put into
182
+ # _jobs_to_analyze_per_function, which essentially makes the keys of this dict being all partially analyzed
183
+ # functions so far. And then when a function does not have any more job to analyze in the future, it will be
184
+ # put in to _completed_functions.
185
+
186
+ # a dict of mapping between function addresses and sets of jobs (include both future jobs and pending jobs)
187
+ # a set is used to speed up the job removal procedure
188
+ self._jobs_to_analyze_per_function = defaultdict(set)
189
+ # addresses of functions that have been completely recovered (i.e. all of its blocks are identified) so far
190
+ self._completed_functions = set()
191
+
192
+ # TODO: A segment tree to speed up CFG node lookups
193
+ self._node_lookup_index = None
194
+ self._node_lookup_index_warned = False
195
+
196
+ self._function_addresses_from_symbols = self._load_func_addrs_from_symbols()
197
+ self._function_addresses_from_eh_frame = self._load_func_addrs_from_eh_frame()
198
+
199
+ # Cache if an object has executable sections or not
200
+ self._object_to_executable_sections = {}
201
+ # Cache if an object has executable segments or not
202
+ self._object_to_executable_segments = {}
203
+
204
+ if model is not None:
205
+ self._model = model
206
+ else:
207
+ self._model: CFGModel = self.kb.cfgs.new_model(self.tag)
208
+
209
+ # necessary warnings
210
+ regions_not_specified = regions is None and binary is None and not objects
211
+ if regions_not_specified and self.project.loader._auto_load_libs and len(self.project.loader.all_objects) > 3:
212
+ l.warning(
213
+ '"auto_load_libs" is enabled. With libraries loaded in project, CFG will cover libraries, '
214
+ "which may take significantly more time than expected. You may reload the binary with "
215
+ '"auto_load_libs" disabled, or specify "regions" to limit the scope of CFG recovery.'
216
+ )
217
+
218
+ if regions is None:
219
+ if self._skip_unmapped_addrs:
220
+ regions = self._executable_memory_regions(objects=objects, force_segment=force_segment)
221
+ else:
222
+ if not objects:
223
+ objects = self.project.loader.all_objects
224
+ regions = [(obj.min_addr, obj.max_addr) for obj in objects]
225
+
226
+ for start, end in regions:
227
+ if end < start:
228
+ raise AngrCFGError("Invalid region bounds (end precedes start)")
229
+
230
+ # Block factory returns patched state by default, so ensure we are also analyzing the patched state
231
+ if self._base_state is None and self.project.kb.patches.values():
232
+ self._base_state = self.project.kb.patches.patched_entry_state
233
+
234
+ if exclude_sparse_regions:
235
+ regions = [r for r in regions if not self._is_region_extremely_sparse(*r, base_state=self._base_state)]
236
+
237
+ if skip_specific_regions:
238
+ if base_state is not None:
239
+ l.warning("You specified both base_state and skip_specific_regions. They may conflict with each other.")
240
+ regions = [r for r in regions if not self._should_skip_region(r[0])]
241
+
242
+ if not regions and self.project.arch.name != "Soot":
243
+ raise AngrCFGError(
244
+ "Regions are empty, or all regions are skipped. You may want to manually specify regions."
245
+ )
246
+
247
+ self._regions_size = sum((end - start) for start, end in regions)
248
+ self._regions: dict[int, int] = SortedDict(regions)
249
+
250
+ l.debug("CFG recovery covers %d regions:", len(self._regions))
251
+ for start, end in self._regions.items():
252
+ l.debug("... %#x - %#x", start, end)
253
+
254
+ def __contains__(self, cfg_node):
255
+ return cfg_node in self.graph
256
+
257
+ #
258
+ # Properties
259
+ #
260
+
261
+ @property
262
+ def _nodes(self):
263
+ return self._model._nodes
264
+
265
+ @property
266
+ def _nodes_by_addr(self):
267
+ return self._model._nodes_by_addr
268
+
269
+ @property
270
+ def model(self) -> CFGModel:
271
+ """
272
+ Get the CFGModel instance.
273
+ :return: The CFGModel instance that this analysis currently uses.
274
+ """
275
+ return self._model
276
+
277
+ @property
278
+ def normalized(self):
279
+ return self._model.normalized
280
+
281
+ @normalized.setter
282
+ def normalized(self, v):
283
+ self._model.normalized = v
284
+
285
+ @property
286
+ def context_sensitivity_level(self):
287
+ return self._context_sensitivity_level
288
+
289
+ @property
290
+ def functions(self):
291
+ """
292
+ A reference to the FunctionManager in the current knowledge base.
293
+
294
+ :return: FunctionManager with all functions
295
+ :rtype: angr.knowledge_plugins.FunctionManager
296
+ """
297
+ return self.kb.functions
298
+
299
+ #
300
+ # Methods
301
+ #
302
+
303
+ def _initialize_cfg(self):
304
+ """
305
+ Re-create the DiGraph
306
+ """
307
+
308
+ self._jobs_to_analyze_per_function = defaultdict(set)
309
+ self._completed_functions = set()
310
+
311
+ def _function_completed(self, func_addr: int):
312
+ pass
313
+
314
+ def _post_analysis(self):
315
+ if self._normalize:
316
+ if not self.normalized:
317
+ self.normalize()
318
+
319
+ # Call normalize() on each function
320
+ for f in self.kb.functions.values():
321
+ if not self.project.is_hooked(f.addr):
322
+ f.normalize()
323
+
324
+ # drop all propagation results that start with "cfg_intermediate"
325
+ self.kb.propagations.discard_by_prefix("cfg_intermediate")
326
+
327
+ def make_copy(self, copy_to):
328
+ """
329
+ Copy self attributes to the new object.
330
+
331
+ :param CFGBase copy_to: The target to copy to.
332
+ :return: None
333
+ """
334
+
335
+ for attr, value in self.__dict__.items():
336
+ if attr.startswith("__") and attr.endswith("__"):
337
+ continue
338
+ setattr(copy_to, attr, value)
339
+
340
+ # pylint: disable=no-self-use
341
+ def copy(self):
342
+ raise NotImplementedError()
343
+
344
+ def output(self):
345
+ raise NotImplementedError()
346
+
347
+ def generate_index(self):
348
+ """
349
+ Generate an index of all nodes in the graph in order to speed up get_any_node() with anyaddr=True.
350
+
351
+ :return: None
352
+ """
353
+
354
+ raise NotImplementedError("I'm too lazy to implement it right now")
355
+
356
+ @deprecated(replacement="self.model.get_predecessors()")
357
+ def get_predecessors(self, cfgnode, excluding_fakeret=True, jumpkind=None):
358
+ return self._model.get_predecessors(cfgnode, excluding_fakeret=excluding_fakeret, jumpkind=jumpkind)
359
+
360
+ @deprecated(replacement="self.model.get_successors()")
361
+ def get_successors(self, node, excluding_fakeret=True, jumpkind=None):
362
+ return self._model.get_successors(node, excluding_fakeret=excluding_fakeret, jumpkind=jumpkind)
363
+
364
+ @deprecated(replacement="self.model.get_successors_and_jumpkind")
365
+ def get_successors_and_jumpkind(self, node, excluding_fakeret=True):
366
+ return self._model.get_successors_and_jumpkind(node, excluding_fakeret=excluding_fakeret)
367
+
368
+ @deprecated(replacement="self.model.get_all_predecessors()")
369
+ def get_all_predecessors(self, cfgnode, depth_limit=None):
370
+ return self._model.get_all_predecessors(cfgnode, depth_limit)
371
+
372
+ @deprecated(replacement="self.model.get_all_successors()")
373
+ def get_all_successors(self, cfgnode, depth_limit=None):
374
+ return self._model.get_all_successors(cfgnode, depth_limit)
375
+
376
+ @deprecated(replacement="self.model.get_node()")
377
+ def get_node(self, block_id):
378
+ return self._model.get_node(block_id)
379
+
380
+ @deprecated(replacement="self.model.get_any_node()")
381
+ def get_any_node(self, addr, is_syscall=None, anyaddr=False, force_fastpath=False):
382
+ return self._model.get_any_node(addr, is_syscall=is_syscall, anyaddr=anyaddr, force_fastpath=force_fastpath)
383
+
384
+ @deprecated(replacement="self.model.get_all_nodes()")
385
+ def get_all_nodes(self, addr, is_syscall=None, anyaddr=False):
386
+ return self._model.get_all_nodes(addr, is_syscall=is_syscall, anyaddr=anyaddr)
387
+
388
+ @deprecated(replacement="self.model.nodes()")
389
+ def nodes(self):
390
+ return self._model.nodes()
391
+
392
+ @deprecated(replacement="nodes")
393
+ def nodes_iter(self):
394
+ """
395
+ (Decrepated) An iterator of all nodes in the graph. Will be removed in the future.
396
+
397
+ :return: The iterator.
398
+ :rtype: iterator
399
+ """
400
+
401
+ return self.nodes()
402
+
403
+ def get_loop_back_edges(self):
404
+ return self._loop_back_edges
405
+
406
+ @deprecated(replacement="self.model.get_branching_nodes()")
407
+ def get_branching_nodes(self):
408
+ return self._model.get_branching_nodes()
409
+
410
+ @deprecated(replacement="self.model.get_exit_stmt_idx")
411
+ def get_exit_stmt_idx(self, src_block, dst_block):
412
+ return self._model.get_exit_stmt_idx(src_block, dst_block)
413
+
414
+ @property
415
+ def graph(self) -> "networkx.DiGraph[CFGNode]":
416
+ raise NotImplementedError()
417
+
418
+ def remove_edge(self, block_from, block_to):
419
+ if self.graph is None:
420
+ raise TypeError("self.graph does not exist.")
421
+
422
+ if block_from not in self.graph:
423
+ raise ValueError("%r is not in CFG." % block_from)
424
+
425
+ if block_to not in self.graph:
426
+ raise ValueError("%r is not in CFG." % block_to)
427
+
428
+ if block_to not in self.graph[block_from]:
429
+ raise ValueError(f"Edge {block_from!r}->{block_to!r} does not exist.")
430
+
431
+ self.graph.remove_edge(block_from, block_to)
432
+
433
+ def _merge_cfgnodes(self, cfgnode_0, cfgnode_1):
434
+ """
435
+ Merge two adjacent CFGNodes into one.
436
+
437
+ :param CFGNode cfgnode_0: The first CFGNode.
438
+ :param CFGNode cfgnode_1: The second CFGNode.
439
+ :return: None
440
+ """
441
+
442
+ assert cfgnode_0.addr + cfgnode_0.size == cfgnode_1.addr
443
+ new_node = cfgnode_0.merge(cfgnode_1)
444
+
445
+ # Update the graph and the nodes dict accordingly
446
+ self._model.remove_node(cfgnode_1.block_id, cfgnode_1)
447
+ self._model.remove_node(cfgnode_0.block_id, cfgnode_0)
448
+
449
+ in_edges = list(self.graph.in_edges(cfgnode_0, data=True))
450
+ out_edges = list(self.graph.out_edges(cfgnode_1, data=True))
451
+
452
+ self.graph.remove_node(cfgnode_0)
453
+ self.graph.remove_node(cfgnode_1)
454
+
455
+ self.graph.add_node(new_node)
456
+ for src, _, data in in_edges:
457
+ self.graph.add_edge(src, new_node, **data)
458
+ for _, dst, data in out_edges:
459
+ self.graph.add_edge(new_node, dst, **data)
460
+
461
+ # Put the new node into node dicts
462
+ self._model.add_node(new_node.block_id, new_node)
463
+
464
+ def _to_snippet(self, cfg_node=None, addr=None, size=None, thumb=False, jumpkind=None, base_state=None):
465
+ """
466
+ Convert a CFGNode instance to a CodeNode object.
467
+
468
+ :param angr.analyses.CFGNode cfg_node: The CFGNode instance.
469
+ :param int addr: Address of the node. Only used when `cfg_node` is None.
470
+ :param bool thumb: Whether this is in THUMB mode or not. Only used for ARM code and when `cfg_node` is None.
471
+ :param str or None jumpkind: Jumpkind of this node.
472
+ :param SimState or None base_state: The state where BlockNode should be created from.
473
+ :return: A converted CodeNode instance.
474
+ :rtype: CodeNode
475
+ """
476
+
477
+ if cfg_node is not None:
478
+ addr = cfg_node.addr
479
+ size = cfg_node.size
480
+ thumb = cfg_node.thumb
481
+
482
+ if addr is None:
483
+ raise ValueError("_to_snippet(): Either cfg_node or addr must be provided.")
484
+
485
+ if self.project.is_hooked(addr) and jumpkind != "Ijk_NoHook":
486
+ hooker = self.project._sim_procedures[addr]
487
+ size = hooker.kwargs.get("length", 0)
488
+ return HookNode(addr, size, type(hooker))
489
+
490
+ if cfg_node is not None:
491
+ return BlockNode(addr, size, thumb=thumb, bytestr=cfg_node.byte_string) # pylint: disable=no-member
492
+ else:
493
+ return self.project.factory.snippet(
494
+ addr, size=size, jumpkind=jumpkind, thumb=thumb, backup_state=base_state
495
+ )
496
+
497
+ def is_thumb_addr(self, addr):
498
+ return addr in self._thumb_addrs
499
+
500
+ def _arm_thumb_filter_jump_successors(self, irsb, successors, get_ins_addr, get_exit_stmt_idx, get_jumpkind):
501
+ """
502
+ Filter successors for THUMB mode basic blocks, and remove those successors that won't be taken normally.
503
+
504
+ :param irsb: The IRSB object.
505
+ :param list successors: A list of successors.
506
+ :param func get_ins_addr: A callable that returns the source instruction address for a successor.
507
+ :param func get_exit_stmt_idx: A callable that returns the source statement ID for a successor.
508
+ :param func get_jumpkind: A callable that returns the jumpkind of a successor.
509
+ :return: A new list of successors after filtering.
510
+ :rtype: list
511
+ """
512
+
513
+ if not successors:
514
+ return []
515
+
516
+ if len(successors) == 1 and get_exit_stmt_idx(successors[0]) == DEFAULT_STATEMENT:
517
+ # only have a default exit. no need to filter
518
+ return successors
519
+
520
+ if irsb.instruction_addresses and all(
521
+ get_ins_addr(suc) == irsb.instruction_addresses[-1] for suc in successors
522
+ ):
523
+ # check if all exits are produced by the last instruction
524
+ # only takes the following jump kinds: Boring, FakeRet, Call, Syscall, Ret
525
+ allowed_jumpkinds = {"Ijk_Boring", "Ijk_FakeRet", "Ijk_Call", "Ijk_Ret"}
526
+ successors = [
527
+ suc
528
+ for suc in successors
529
+ if get_jumpkind(suc) in allowed_jumpkinds or get_jumpkind(suc).startswith("Ijk_Sys")
530
+ ]
531
+ if len(successors) == 1:
532
+ return successors
533
+
534
+ can_produce_exits = set() # addresses of instructions that can produce exits
535
+ bb = self._lift(irsb.addr, size=irsb.size, thumb=True)
536
+
537
+ # step A: filter exits using capstone (since it's faster than re-lifting the entire block to VEX)
538
+ THUMB_BRANCH_INSTRUCTIONS = {
539
+ "beq",
540
+ "bne",
541
+ "bcs",
542
+ "bhs",
543
+ "bcc",
544
+ "blo",
545
+ "bmi",
546
+ "bpl",
547
+ "bvs",
548
+ "bvc",
549
+ "bhi",
550
+ "bls",
551
+ "bge",
552
+ "blt",
553
+ "bgt",
554
+ "ble",
555
+ "cbz",
556
+ "cbnz",
557
+ }
558
+ for cs_insn in bb.capstone.insns:
559
+ if cs_insn.mnemonic.split(".")[0] in THUMB_BRANCH_INSTRUCTIONS:
560
+ can_produce_exits.add(cs_insn.address)
561
+
562
+ if all(
563
+ get_ins_addr(suc) in can_produce_exits or get_exit_stmt_idx(suc) == DEFAULT_STATEMENT for suc in successors
564
+ ):
565
+ # nothing will be filtered.
566
+ return successors
567
+
568
+ # step B: consider VEX statements
569
+ it_counter = 0
570
+ conc_temps = {}
571
+
572
+ for stmt in bb.vex.statements:
573
+ if stmt.tag == "Ist_IMark":
574
+ if it_counter > 0:
575
+ it_counter -= 1
576
+ can_produce_exits.add(stmt.addr + stmt.delta)
577
+ elif stmt.tag == "Ist_WrTmp":
578
+ val = stmt.data
579
+ if val.tag == "Iex_Const":
580
+ conc_temps[stmt.tmp] = val.con.value
581
+ elif stmt.tag == "Ist_Put":
582
+ if stmt.offset == self.project.arch.registers["itstate"][0]:
583
+ val = stmt.data
584
+ if val.tag == "Iex_RdTmp":
585
+ if val.tmp in conc_temps:
586
+ # We found an IT instruction!!
587
+ # Determine how many instructions are conditional
588
+ it_counter = 0
589
+ itstate = conc_temps[val.tmp]
590
+ while itstate != 0:
591
+ it_counter += 1
592
+ itstate >>= 8
593
+ elif val.tag == "Iex_Const":
594
+ it_counter = 0
595
+ itstate = val.con.value
596
+ while itstate != 0:
597
+ it_counter += 1
598
+ itstate >>= 8
599
+
600
+ if it_counter != 0:
601
+ l.debug("Basic block ends before calculated IT block (%#x)", irsb.addr)
602
+
603
+ successors_filtered = [
604
+ suc
605
+ for suc in successors
606
+ if get_ins_addr(suc) in can_produce_exits or get_exit_stmt_idx(suc) == DEFAULT_STATEMENT
607
+ ]
608
+
609
+ return successors_filtered
610
+
611
+ # Methods for determining scanning scope
612
+
613
+ def _inside_regions(self, address: int | None) -> bool:
614
+ """
615
+ Check if the address is inside any existing region.
616
+
617
+ :param int address: Address to check.
618
+ :return: True if the address is within one of the memory regions, False otherwise.
619
+ """
620
+
621
+ try:
622
+ start_addr = next(self._regions.irange(maximum=address, reverse=True))
623
+ except StopIteration:
624
+ return False
625
+ else:
626
+ return address < self._regions[start_addr]
627
+
628
+ def _get_min_addr(self) -> int | None:
629
+ """
630
+ Get the minimum address out of all regions. We assume self._regions is sorted.
631
+
632
+ :return: The minimum address, or None if there is no such address.
633
+ """
634
+
635
+ if not self._regions:
636
+ if self.project.arch.name != "Soot":
637
+ l.error("self._regions is empty or not properly set.")
638
+ return None
639
+
640
+ return next(self._regions.irange())
641
+
642
+ def _next_address_in_regions(self, address: int | None) -> int | None:
643
+ """
644
+ Return the next immediate address that is inside any of the regions.
645
+
646
+ :param address: The address to start scanning.
647
+ :return: The next address that is inside one of the memory regions, or None if there is no such address.
648
+ """
649
+
650
+ if self._inside_regions(address):
651
+ return address
652
+
653
+ try:
654
+ return next(self._regions.irange(minimum=address, reverse=False))
655
+ except StopIteration:
656
+ return None
657
+
658
+ def _is_region_extremely_sparse(self, start: int, end: int, base_state: Optional["SimState"] = None) -> bool:
659
+ """
660
+ Check whether the given memory region is extremely sparse, i.e., all bytes are the same value.
661
+
662
+ :param start: The beginning of the region.
663
+ :param end: The end of the region (exclusive).
664
+ :param base_state: The base state (optional).
665
+ :return: True if the region is extremely sparse, False otherwise.
666
+ """
667
+
668
+ all_bytes = None
669
+
670
+ if base_state is not None:
671
+ all_bytes = base_state.memory.load(start, end - start)
672
+ try:
673
+ all_bytes = base_state.solver.eval(all_bytes, cast_to=bytes)
674
+ except SimError:
675
+ all_bytes = None
676
+
677
+ size = end - start
678
+
679
+ if all_bytes is None:
680
+ # load from the binary
681
+ all_bytes = self._fast_memory_load_bytes(start, size)
682
+
683
+ if all_bytes is None:
684
+ # failed to load bytes in this region. it might be because the region is not fully mapped (i.e., there are
685
+ # holes). we assume this region is good for analysis.
686
+ return False
687
+
688
+ if len(all_bytes) < size:
689
+ l.warning(
690
+ "_is_region_extremely_sparse: The given region %#x-%#x is not a continuous memory region in the "
691
+ "memory space. Only the first %d bytes (%#x-%#x) are processed.",
692
+ start,
693
+ end,
694
+ len(all_bytes),
695
+ start,
696
+ start + len(all_bytes),
697
+ )
698
+
699
+ the_byte_value = None
700
+ for b in all_bytes:
701
+ if the_byte_value is None:
702
+ the_byte_value = b
703
+ else:
704
+ if the_byte_value != b:
705
+ return False
706
+
707
+ return True
708
+
709
+ def _should_skip_region(self, region_start):
710
+ """
711
+ Some regions usually do not contain any executable code, but are still marked as executable. We should skip
712
+ those regions by default.
713
+
714
+ :param int region_start: Address of the beginning of the region.
715
+ :return: True/False
716
+ :rtype: bool
717
+ """
718
+
719
+ obj = self.project.loader.find_object_containing(region_start, membership_check=False)
720
+ if obj is None:
721
+ return False
722
+ if isinstance(obj, PE):
723
+ section = obj.find_section_containing(region_start)
724
+ if section is None:
725
+ return False
726
+ if section.name in {".textbss"}:
727
+ return True
728
+
729
+ return False
730
+
731
+ def _executable_memory_regions(self, objects=None, force_segment=False):
732
+ """
733
+ Get all executable memory regions from the binaries
734
+
735
+ :param objects: A collection of binary objects to collect regions from. If None, regions from all project
736
+ binary objects are used.
737
+ :param bool force_segment: Rely on binary segments instead of sections.
738
+ :return: A sorted list of tuples (beginning_address, end_address)
739
+ """
740
+
741
+ if objects is None:
742
+ binaries = self.project.loader.all_objects
743
+ else:
744
+ binaries = objects
745
+
746
+ memory_regions = []
747
+
748
+ for b in binaries:
749
+ if isinstance(b, ELF):
750
+ # If we have sections, we get result from sections
751
+ sections = []
752
+ if not force_segment and b.sections:
753
+ # Get all executable sections
754
+ for section in b.sections:
755
+ if section.is_executable:
756
+ tpl = (section.min_addr, section.max_addr + 1)
757
+ sections.append(tpl)
758
+ memory_regions += sections
759
+
760
+ segments = []
761
+ # Get all executable segments
762
+ for segment in b.segments:
763
+ if segment.is_executable:
764
+ tpl = (segment.min_addr, segment.max_addr + 1)
765
+ segments.append(tpl)
766
+ if sections and segments:
767
+ # are there executable segments with no sections inside?
768
+ for segment in segments:
769
+ for section in sections:
770
+ if segment[0] <= section[0] < segment[1]:
771
+ break
772
+ else:
773
+ memory_regions.append(segment)
774
+
775
+ elif isinstance(b, (Coff, PE)):
776
+ for section in b.sections:
777
+ if section.is_executable:
778
+ tpl = (section.min_addr, section.max_addr + 1)
779
+ memory_regions.append(tpl)
780
+
781
+ elif isinstance(b, XBE):
782
+ # some XBE files will mark the data sections as executable
783
+ for section in b.sections:
784
+ if (
785
+ section.is_executable
786
+ and not section.is_writable
787
+ and section.name not in {".data", ".rdata", ".rodata"}
788
+ ):
789
+ tpl = (section.min_addr, section.max_addr + 1)
790
+ memory_regions.append(tpl)
791
+
792
+ elif isinstance(b, MachO):
793
+ if b.segments:
794
+ # Get all executable segments
795
+ for seg in b.segments:
796
+ if seg.is_executable:
797
+ # Take all sections from this segment (MachO style)
798
+ for section in seg.sections:
799
+ tpl = (section.min_addr, section.max_addr + 1)
800
+ memory_regions.append(tpl)
801
+
802
+ elif isinstance(b, (Hex, SRec)):
803
+ if b.regions:
804
+ for region_addr, region_size in b.regions:
805
+ memory_regions.append((region_addr, region_addr + region_size))
806
+
807
+ elif isinstance(b, Blob):
808
+ # a blob is entirely executable
809
+ tpl = (b.min_addr, b.max_addr + 1)
810
+ memory_regions.append(tpl)
811
+
812
+ elif isinstance(b, NamedRegion):
813
+ # NamedRegions have no content! Ignore
814
+ pass
815
+
816
+ elif isinstance(b, self._cle_pseudo_objects):
817
+ pass
818
+
819
+ else:
820
+ l.warning('Unsupported object format "%s". Treat it as an executable.', b.__class__.__name__)
821
+
822
+ tpl = (b.min_addr, b.max_addr + 1)
823
+ memory_regions.append(tpl)
824
+
825
+ if not memory_regions:
826
+ memory_regions = [(start, start + len(backer)) for start, backer in self.project.loader.memory.backers()]
827
+
828
+ memory_regions = sorted(memory_regions, key=lambda x: x[0])
829
+
830
+ return memory_regions
831
+
832
+ def _addr_in_exec_memory_regions(self, addr):
833
+ """
834
+ Test if the address belongs to an executable memory region.
835
+
836
+ :param int addr: The address to test
837
+ :return: True if the address belongs to an exectubale memory region, False otherwise
838
+ :rtype: bool
839
+ """
840
+
841
+ for start, end in self._exec_mem_regions:
842
+ if start <= addr < end:
843
+ return True
844
+ return False
845
+
846
+ def _addrs_belong_to_same_section(self, addr_a, addr_b):
847
+ """
848
+ Test if two addresses belong to the same section.
849
+
850
+ :param int addr_a: The first address to test.
851
+ :param int addr_b: The second address to test.
852
+ :return: True if the two addresses belong to the same section or both of them do not belong to any
853
+ section, False otherwise.
854
+ :rtype: bool
855
+ """
856
+
857
+ obj = self.project.loader.find_object_containing(addr_a, membership_check=False)
858
+
859
+ if obj is None:
860
+ # test if addr_b also does not belong to any object
861
+ obj_b = self.project.loader.find_object_containing(addr_b, membership_check=False)
862
+ if obj_b is None:
863
+ return True
864
+ return False
865
+
866
+ src_section = obj.find_section_containing(addr_a)
867
+ if src_section is None:
868
+ # test if addr_b also does not belong to any section
869
+ dst_section = obj.find_section_containing(addr_b)
870
+ if dst_section is None:
871
+ return self._addrs_belong_to_same_segment(addr_a, addr_b)
872
+ return False
873
+
874
+ return src_section.contains_addr(addr_b)
875
+
876
+ def _addrs_belong_to_same_segment(self, addr_a, addr_b):
877
+ """
878
+ Test if two addresses belong to the same segment.
879
+
880
+ :param int addr_a: The first address to test.
881
+ :param int addr_b: The second address to test.
882
+ :return: True if the two addresses belong to the same segment or both of them do not belong to any
883
+ section, False otherwise.
884
+ :rtype: bool
885
+ """
886
+
887
+ obj = self.project.loader.find_object_containing(addr_a, membership_check=False)
888
+
889
+ if obj is None:
890
+ # test if addr_b also does not belong to any object
891
+ obj_b = self.project.loader.find_object_containing(addr_b, membership_check=False)
892
+ if obj_b is None:
893
+ return True
894
+ return False
895
+
896
+ src_segment = obj.find_segment_containing(addr_a)
897
+ if src_segment is None:
898
+ # test if addr_b also does not belong to any section
899
+ dst_segment = obj.find_segment_containing(addr_b)
900
+ if dst_segment is None:
901
+ return True
902
+ return False
903
+
904
+ return src_segment.contains_addr(addr_b)
905
+
906
+ def _object_has_executable_sections(self, obj):
907
+ """
908
+ Check whether an object has at least one executable section.
909
+
910
+ :param cle.Backend obj: The object to test.
911
+ :return: None
912
+ """
913
+
914
+ if obj in self._object_to_executable_sections:
915
+ return self._object_to_executable_sections[obj]
916
+ r = any(sec.is_executable for sec in obj.sections)
917
+ self._object_to_executable_sections[obj] = r
918
+ return r
919
+
920
+ def _object_has_executable_segments(self, obj):
921
+ """
922
+ Check whether an object has at least one executable segment.
923
+
924
+ :param cle.Backend obj: The object to test.
925
+ :return: None
926
+ """
927
+
928
+ if obj in self._object_to_executable_segments:
929
+ return self._object_to_executable_segments[obj]
930
+ r = any(seg.is_executable for seg in obj.segments)
931
+ self._object_to_executable_segments[obj] = r
932
+ return r
933
+
934
+ def _addr_hooked_or_syscall(self, addr):
935
+ """
936
+ Check whether the address belongs to a hook or a syscall.
937
+
938
+ :param int addr: The address to check.
939
+ :return: True if the address is hooked or belongs to a syscall. False otherwise.
940
+ :rtype: bool
941
+ """
942
+
943
+ return self.project.is_hooked(addr) or self.project.simos.is_syscall_addr(addr)
944
+
945
+ def _fast_memory_load_byte(self, addr):
946
+ """
947
+ Perform a fast memory loading of a byte.
948
+
949
+ :param int addr: Address to read from.
950
+ :return: A char or None if the address does not exist.
951
+ :rtype: int or None
952
+ """
953
+
954
+ try:
955
+ return self.project.loader.memory[addr]
956
+ except KeyError:
957
+ return None
958
+
959
+ def _fast_memory_load_bytes(self, addr, length):
960
+ """
961
+ Perform a fast memory loading of some data.
962
+
963
+ :param int addr: Address to read from.
964
+ :param int length: Size of the string to load.
965
+ :return: A string or None if the address does not exist.
966
+ :rtype: bytes or None
967
+ """
968
+
969
+ try:
970
+ return self.project.loader.memory.load(addr, length)
971
+ except KeyError:
972
+ return None
973
+
974
+ def _fast_memory_load_pointer(self, addr, size=None):
975
+ """
976
+ Perform a fast memory loading of a pointer.
977
+
978
+ :param int addr: Address to read from.
979
+ :param int size: Size of the pointer. Default to machine-word size.
980
+ :return: A pointer or None if the address does not exist.
981
+ :rtype: int
982
+ """
983
+
984
+ try:
985
+ return self.project.loader.memory.unpack_word(addr, size=size)
986
+ except KeyError:
987
+ return None
988
+
989
+ def _load_func_addrs_from_symbols(self):
990
+ """
991
+ Get all possible function addresses that are specified by the symbols in the binary
992
+
993
+ :return: A set of addresses that are probably functions
994
+ :rtype: set
995
+ """
996
+
997
+ return {sym.rebased_addr for sym in self._binary.symbols if sym.is_function}
998
+
999
+ def _load_func_addrs_from_eh_frame(self):
1000
+ """
1001
+ Get possible function addresses from .eh_frame.
1002
+
1003
+ :return: A set of addresses that are probably functions.
1004
+ :rtype: set
1005
+ """
1006
+
1007
+ addrs = set()
1008
+ if isinstance(self._binary, ELF) and self._binary.has_dwarf_info:
1009
+ for function_hint in self._binary.function_hints:
1010
+ if function_hint.source == FunctionHintSource.EH_FRAME:
1011
+ addrs.add(function_hint.addr)
1012
+ return addrs
1013
+
1014
+ #
1015
+ # Analyze function features
1016
+ #
1017
+
1018
+ def _determine_function_returning(self, func, all_funcs_completed=False):
1019
+ """
1020
+ Determine if a function returns or not.
1021
+
1022
+ A function does not return if
1023
+ a) it is a SimProcedure that has NO_RET being True,
1024
+ or
1025
+ b) it is completely recovered (i.e. every block of this function has been recovered, and no future block will
1026
+ be added to it), and it does not have a ret or any equivalent instruction.
1027
+
1028
+ A function returns if any of its block contains a ret instruction or any equivalence.
1029
+
1030
+ :param Function func: The function to work on.
1031
+ :param bool all_funcs_completed: Whether we treat all functions as completed functions or not.
1032
+ :return: True if the function returns, False if the function does not return, or None if it is
1033
+ not yet determinable with the information available at the moment.
1034
+ :rtype: bool or None
1035
+ """
1036
+
1037
+ if not self._inside_regions(func.addr):
1038
+ # we don't have a full view of this function. assume it returns
1039
+ return True
1040
+
1041
+ # If there is at least one return site, then this function is definitely returning
1042
+ if func.has_return:
1043
+ return True
1044
+
1045
+ # Let's first see if it's a known SimProcedure that does not return
1046
+ if self.project.is_hooked(func.addr):
1047
+ procedure = self.project.hooked_by(func.addr)
1048
+ else:
1049
+ try:
1050
+ procedure = self.project.simos.syscall_from_addr(func.addr, allow_unsupported=False)
1051
+ except AngrUnsupportedSyscallError:
1052
+ procedure = None
1053
+
1054
+ if procedure is not None and hasattr(procedure, "NO_RET"):
1055
+ return not procedure.NO_RET
1056
+
1057
+ # did we finish analyzing this function?
1058
+ if not all_funcs_completed and func.addr not in self._completed_functions:
1059
+ return None
1060
+
1061
+ if not func.block_addrs_set:
1062
+ # there is no block inside this function
1063
+ # it might happen if the function has been incorrectly identified as part of another function
1064
+ # the error will be corrected during post-processing. In fact at this moment we cannot say anything
1065
+ # about whether this function returns or not. We always assume it returns.
1066
+ return True
1067
+
1068
+ bail_out = False
1069
+
1070
+ # if this function has jump-out sites or ret-out sites, it returns as long as any of the target function
1071
+ # returns
1072
+ for goout_site, type_ in [(site, "jumpout") for site in func.jumpout_sites] + [
1073
+ (site, "retout") for site in func.retout_sites
1074
+ ]:
1075
+ # determine where it jumps/returns to
1076
+ goout_site_successors = goout_site.successors()
1077
+ # Filter out UnresolvableJumpTarget because those don't mean that we actually know where it jumps to
1078
+ known_successors = [
1079
+ n
1080
+ for n in goout_site_successors
1081
+ if not (isinstance(n, HookNode) and n.sim_procedure == UnresolvableJumpTarget)
1082
+ ]
1083
+
1084
+ if not known_successors:
1085
+ # not sure where it jumps to. bail out
1086
+ bail_out = True
1087
+ continue
1088
+
1089
+ # for ret-out sites, determine what function it calls
1090
+ if type_ == "retout":
1091
+ # see whether the function being called returns or not
1092
+ func_successors = [succ for succ in goout_site_successors if isinstance(succ, Function)]
1093
+ if func_successors and all(
1094
+ func_successor.returning in (None, False) for func_successor in func_successors
1095
+ ):
1096
+ # the returning of all possible function calls are undetermined, or they do not return
1097
+ # ignore this site
1098
+ continue
1099
+
1100
+ if type_ == "retout":
1101
+ goout_target = next((succ for succ in goout_site_successors if not isinstance(succ, Function)), None)
1102
+ else:
1103
+ goout_target = next((succ for succ in goout_site_successors), None)
1104
+ if goout_target is None:
1105
+ # there is no jumpout site, which is weird, but what can we do...
1106
+ continue
1107
+ if not self.kb.functions.contains_addr(goout_target.addr):
1108
+ # wait it does not jump to a function?
1109
+ bail_out = True
1110
+ continue
1111
+
1112
+ target_func = self.kb.functions[goout_target.addr]
1113
+ if target_func.returning is True:
1114
+ return True
1115
+ elif target_func.returning is None:
1116
+ # the returning status of at least one of the target functions is not decided yet.
1117
+ bail_out = True
1118
+
1119
+ if bail_out:
1120
+ # We cannot determine at this point. bail out
1121
+ return None
1122
+
1123
+ # well this function does not return then
1124
+ return False
1125
+
1126
+ def _analyze_function_features(self, all_funcs_completed=False):
1127
+ """
1128
+ For each function in the function_manager, try to determine if it returns or not. A function does not return if
1129
+ it calls another function that is known to be not returning, and this function does not have other exits.
1130
+
1131
+ We might as well analyze other features of functions in the future.
1132
+
1133
+ :param bool all_funcs_completed: Ignore _completed_functions set and treat all functions as completed. This
1134
+ can be set to True after the entire CFG is built and _post_analysis() is
1135
+ called (at which point analysis on all functions must be completed).
1136
+ """
1137
+
1138
+ changes = {"functions_return": [], "functions_do_not_return": []}
1139
+
1140
+ if self._updated_nonreturning_functions is not None:
1141
+ all_func_addrs = self._updated_nonreturning_functions
1142
+
1143
+ # Convert addresses to objects
1144
+ all_functions = [
1145
+ self.kb.functions.get_by_addr(f) for f in all_func_addrs if self.kb.functions.contains_addr(f)
1146
+ ]
1147
+
1148
+ else:
1149
+ all_functions = list(self.kb.functions.values())
1150
+
1151
+ analyzed_functions = set()
1152
+ # short-hand
1153
+ functions: FunctionManager = self.kb.functions
1154
+
1155
+ while all_functions:
1156
+ func: Function = all_functions.pop(-1)
1157
+ analyzed_functions.add(func.addr)
1158
+
1159
+ if func.returning is not None:
1160
+ # It has been determined before. Skip it
1161
+ continue
1162
+
1163
+ returning = self._determine_function_returning(func, all_funcs_completed=all_funcs_completed)
1164
+
1165
+ if returning:
1166
+ func.returning = True
1167
+ changes["functions_return"].append(func)
1168
+ elif returning is False:
1169
+ func.returning = False
1170
+ changes["functions_do_not_return"].append(func)
1171
+
1172
+ if returning is not None:
1173
+ # Add all callers of this function to all_functions list
1174
+ if func.addr in functions.callgraph:
1175
+ callers = functions.callgraph.predecessors(func.addr)
1176
+ for caller in callers:
1177
+ if caller in analyzed_functions:
1178
+ continue
1179
+ if functions.contains_addr(caller):
1180
+ all_functions.append(functions.get_by_addr(caller))
1181
+
1182
+ return changes
1183
+
1184
+ def _iteratively_analyze_function_features(self, all_funcs_completed=False):
1185
+ """
1186
+ Iteratively analyze function features until a fixed point is reached.
1187
+
1188
+ :return: the "changes" dict
1189
+ :rtype: dict
1190
+ """
1191
+
1192
+ changes = {"functions_do_not_return": set(), "functions_return": set()}
1193
+
1194
+ while True:
1195
+ new_changes = self._analyze_function_features(all_funcs_completed=all_funcs_completed)
1196
+
1197
+ changes["functions_do_not_return"] |= set(new_changes["functions_do_not_return"])
1198
+ changes["functions_return"] |= set(new_changes["functions_return"])
1199
+
1200
+ if not new_changes["functions_do_not_return"] and not new_changes["functions_return"]:
1201
+ # a fixed point is reached
1202
+ break
1203
+
1204
+ return changes
1205
+
1206
+ def normalize(self):
1207
+ """
1208
+ Normalize the CFG, making sure that there are no overlapping basic blocks.
1209
+
1210
+ Note that this method will not alter transition graphs of each function in self.kb.functions. You may call
1211
+ normalize() on each Function object to normalize their transition graphs.
1212
+
1213
+ :return: None
1214
+ """
1215
+
1216
+ graph = self.graph
1217
+
1218
+ smallest_nodes = {} # indexed by end address of the node
1219
+ end_addresses_to_nodes = defaultdict(set)
1220
+
1221
+ for n in graph.nodes():
1222
+ if n.is_simprocedure:
1223
+ continue
1224
+ end_addr = n.addr + n.size
1225
+ key = (end_addr, n.callstack_key)
1226
+ # add the new item
1227
+ end_addresses_to_nodes[key].add(n)
1228
+
1229
+ for key in list(end_addresses_to_nodes.keys()):
1230
+ if len(end_addresses_to_nodes[key]) == 1:
1231
+ smallest_nodes[key] = next(iter(end_addresses_to_nodes[key]))
1232
+ del end_addresses_to_nodes[key]
1233
+
1234
+ while end_addresses_to_nodes:
1235
+ key_to_find = (None, None)
1236
+ for tpl, x in end_addresses_to_nodes.items():
1237
+ if len(x) > 1:
1238
+ key_to_find = tpl
1239
+ break
1240
+
1241
+ end_addr, callstack_key = key_to_find
1242
+ all_nodes = end_addresses_to_nodes[key_to_find]
1243
+
1244
+ all_nodes = sorted(all_nodes, key=lambda node: node.addr, reverse=True)
1245
+ smallest_node = all_nodes[0] # take the one that has the highest address
1246
+ other_nodes = all_nodes[1:]
1247
+
1248
+ self._normalize_core(
1249
+ graph, callstack_key, smallest_node, other_nodes, smallest_nodes, end_addresses_to_nodes
1250
+ )
1251
+
1252
+ del end_addresses_to_nodes[key_to_find]
1253
+ # make sure the smallest node is stored in end_addresses
1254
+ smallest_nodes[key_to_find] = smallest_node
1255
+
1256
+ # corner case
1257
+ # sometimes two overlapping blocks may not be ending at the instruction. this might happen when one of the
1258
+ # blocks (the bigger one) hits the instruction count limit or bytes limit before reaching the end address
1259
+ # of the smaller block. in this case we manually pick up those blocks.
1260
+ if not end_addresses_to_nodes:
1261
+ # find if there are still overlapping blocks
1262
+ sorted_smallest_nodes = defaultdict(list) # callstack_key is the key of this dict
1263
+ for k, node in smallest_nodes.items():
1264
+ _, callstack_key = k
1265
+ sorted_smallest_nodes[callstack_key].append(node)
1266
+ for k in sorted_smallest_nodes.keys():
1267
+ sorted_smallest_nodes[k] = sorted(sorted_smallest_nodes[k], key=lambda node: node.addr)
1268
+
1269
+ for callstack_key, lst in sorted_smallest_nodes.items():
1270
+ lst_len = len(lst)
1271
+ for i, node in enumerate(lst):
1272
+ if i == lst_len - 1:
1273
+ break
1274
+ next_node = lst[i + 1]
1275
+ if node is not next_node and node.addr <= next_node.addr < node.addr + node.size:
1276
+ # umm, those nodes are overlapping, but they must have different end addresses
1277
+ nodekey_a = node.addr + node.size, callstack_key
1278
+ nodekey_b = next_node.addr + next_node.size, callstack_key
1279
+ if nodekey_a == nodekey_b:
1280
+ # error handling: this will only happen if we have completely overlapping nodes
1281
+ # caused by different jumps (one of the jumps is probably incorrect), which usually
1282
+ # indicates an error in CFG recovery. we print a warning and skip this node
1283
+ l.warning(
1284
+ "Found completely overlapping nodes %s. It usually indicates an error in CFG "
1285
+ "recovery. Skip.",
1286
+ node,
1287
+ )
1288
+ continue
1289
+
1290
+ if nodekey_a in smallest_nodes and nodekey_b in smallest_nodes:
1291
+ # misuse end_addresses_to_nodes
1292
+ end_addresses_to_nodes[(node.addr + node.size, callstack_key)].add(node)
1293
+ end_addresses_to_nodes[(node.addr + node.size, callstack_key)].add(next_node)
1294
+
1295
+ smallest_nodes.pop(nodekey_a, None)
1296
+ smallest_nodes.pop(nodekey_b, None)
1297
+
1298
+ self.normalized = True
1299
+
1300
+ def _normalize_core(
1301
+ self,
1302
+ graph: "networkx.DiGraph[CFGNode]",
1303
+ callstack_key,
1304
+ smallest_node,
1305
+ other_nodes,
1306
+ smallest_nodes,
1307
+ end_addresses_to_nodes,
1308
+ ):
1309
+ # Break other nodes
1310
+ for n in other_nodes:
1311
+ new_size = get_real_address_if_arm(self.project.arch, smallest_node.addr) - get_real_address_if_arm(
1312
+ self.project.arch, n.addr
1313
+ )
1314
+ if new_size == 0:
1315
+ # This node has the same size as the smallest one. Don't touch it.
1316
+ continue
1317
+
1318
+ new_end_addr = n.addr + new_size
1319
+
1320
+ # Does it already exist?
1321
+ new_node = None
1322
+ key = (new_end_addr, n.callstack_key)
1323
+ # the logic below is a little convoluted. we check if key exists in either end_address_to_nodes or
1324
+ # smallest_nodes, since we don't always add the new node back to end_addresses_to_nodes dict - we only do so
1325
+ # when there are more than one node with that key.
1326
+ if key in end_addresses_to_nodes:
1327
+ new_node = next((i for i in end_addresses_to_nodes[key] if i.addr == n.addr), None)
1328
+ if new_node is None:
1329
+ if key in smallest_nodes and smallest_nodes[key].addr == n.addr:
1330
+ new_node = smallest_nodes[key]
1331
+
1332
+ if new_node is None:
1333
+ # Create a new one
1334
+ if self.tag == "CFGFast":
1335
+ new_node = CFGNode(
1336
+ n.addr,
1337
+ new_size,
1338
+ self.model,
1339
+ function_address=n.function_address,
1340
+ block_id=n.block_id,
1341
+ instruction_addrs=[i for i in n.instruction_addrs if n.addr <= i <= n.addr + new_size],
1342
+ thumb=n.thumb,
1343
+ )
1344
+ elif self.tag == "CFGEmulated":
1345
+ new_node = CFGENode(
1346
+ n.addr,
1347
+ new_size,
1348
+ self.model,
1349
+ callstack_key=callstack_key,
1350
+ function_address=n.function_address,
1351
+ block_id=n.block_id,
1352
+ instruction_addrs=[i for i in n.instruction_addrs if n.addr <= i <= n.addr + new_size],
1353
+ thumb=n.thumb,
1354
+ )
1355
+ else:
1356
+ raise ValueError("Unknown tag %s." % self.tag)
1357
+
1358
+ # Copy instruction addresses
1359
+ new_node.instruction_addrs = [
1360
+ ins_addr for ins_addr in n.instruction_addrs if ins_addr < n.addr + new_size
1361
+ ]
1362
+ # Put the new node into end_addresses list
1363
+ if key in smallest_nodes:
1364
+ end_addresses_to_nodes[key].add(smallest_nodes[key])
1365
+ end_addresses_to_nodes[key].add(new_node)
1366
+ else:
1367
+ smallest_nodes[key] = new_node
1368
+
1369
+ # Modify the CFG
1370
+ original_predecessors = list(graph.in_edges([n], data=True))
1371
+ original_successors = list(graph.out_edges([n], data=True))
1372
+
1373
+ if smallest_node not in graph:
1374
+ continue
1375
+
1376
+ for _s, d, data in original_successors:
1377
+ ins_addr = data.get("ins_addr", None) # ins_addr might be None for FakeRet edges
1378
+ if ins_addr is None and data.get("jumpkind", None) != "Ijk_FakeRet":
1379
+ l.warning(
1380
+ "Unexpected edge with ins_addr being None: %s -> %s, data = %s.",
1381
+ _s,
1382
+ d,
1383
+ str(data),
1384
+ )
1385
+ if ins_addr is not None and ins_addr < smallest_node.addr:
1386
+ continue
1387
+ if d not in graph[smallest_node]:
1388
+ if d is n:
1389
+ graph.add_edge(smallest_node, new_node, **data)
1390
+ else:
1391
+ graph.add_edge(smallest_node, d, **data)
1392
+
1393
+ for p, _, _ in original_predecessors:
1394
+ graph.remove_edge(p, n)
1395
+ if n in graph:
1396
+ graph.remove_node(n)
1397
+
1398
+ # Update nodes dict
1399
+ self._model.remove_node(n.block_id, n)
1400
+ self._model.add_node(n.block_id, new_node)
1401
+
1402
+ for p, _, data in original_predecessors:
1403
+ # Consider the following case: two basic blocks ending at the same position, where A is larger, and
1404
+ # B is smaller. Suppose there is an edge going from the end of A to A itself, and apparently there
1405
+ # is another edge from B to A as well. After splitting A into A' and B, we DO NOT want to add A back
1406
+ # in, otherwise there will be an edge from A to A`, while A should totally be got rid of in the new
1407
+ # graph.
1408
+ if p not in other_nodes:
1409
+ graph.add_edge(p, new_node, **data)
1410
+
1411
+ # We should find the correct successor
1412
+ new_successors = [i for i in [smallest_node] + other_nodes if i.addr == smallest_node.addr]
1413
+ if new_successors:
1414
+ new_successor = new_successors[0]
1415
+ graph.add_edge(
1416
+ new_node,
1417
+ new_successor,
1418
+ jumpkind="Ijk_Boring",
1419
+ ins_addr=new_node.instruction_addrs[-1] if new_node.instruction_addrs else new_node.addr,
1420
+ )
1421
+ else:
1422
+ # We gotta create a new one
1423
+ l.error("normalize(): Please report it to Fish.")
1424
+
1425
+ # deal with duplicated entries in self.jump_tables and self.indirect_jumps
1426
+ if smallest_node.addr in self.model.jump_tables:
1427
+ for n in other_nodes:
1428
+ if n.addr in self.model.jump_tables:
1429
+ del self.model.jump_tables[n.addr]
1430
+ if smallest_node.addr in self.indirect_jumps:
1431
+ for n in other_nodes:
1432
+ if n.addr in self.indirect_jumps:
1433
+ del self.indirect_jumps[n.addr]
1434
+
1435
+ #
1436
+ # Job management
1437
+ #
1438
+
1439
+ def _register_analysis_job(self, func_addr, job):
1440
+ """
1441
+ Register an analysis job of a function to job manager. This allows us to track whether we have finished
1442
+ analyzing/recovering a function or not.
1443
+
1444
+ :param int func_addr: Address of the function that this job belongs to.
1445
+ :param job: The job to register. Note that it does not necessarily be the a CFGJob instance. There
1446
+ can be PendingJob or PendingJob or other instances, too.
1447
+ :return: None
1448
+ """
1449
+
1450
+ self._jobs_to_analyze_per_function[func_addr].add(job)
1451
+
1452
+ def _deregister_analysis_job(self, func_addr, job):
1453
+ """
1454
+ Deregister/Remove an analysis job of a function from job manager.
1455
+
1456
+ :param int func_addr: Address of the function that this job belongs to.
1457
+ :param job: The job to deregister.
1458
+ :return: None
1459
+ """
1460
+
1461
+ self._jobs_to_analyze_per_function[func_addr].discard(job)
1462
+
1463
+ def _get_finished_functions(self):
1464
+ """
1465
+ Obtain all functions of which we have finished analyzing. As _jobs_to_analyze_per_function is a defaultdict(),
1466
+ if a function address shows up in it with an empty job list, we consider we have exhausted all jobs of this
1467
+ function (both current jobs and pending jobs), thus the analysis of this function is done.
1468
+
1469
+ :return: a list of function addresses of that we have finished analysis.
1470
+ :rtype: list
1471
+ """
1472
+
1473
+ finished_func_addrs = []
1474
+ for func_addr, all_jobs in self._jobs_to_analyze_per_function.items():
1475
+ if not all_jobs:
1476
+ # great! we have finished analyzing this function!
1477
+ finished_func_addrs.append(func_addr)
1478
+
1479
+ return finished_func_addrs
1480
+
1481
+ def _cleanup_analysis_jobs(self, finished_func_addrs=None):
1482
+ """
1483
+ From job manager, remove all functions of which we have finished analysis.
1484
+
1485
+ :param list or None finished_func_addrs: A list of addresses of functions of which we have finished analysis.
1486
+ A new list of function addresses will be obtained by calling
1487
+ _get_finished_functions() if this parameter is None.
1488
+ :return: None
1489
+ """
1490
+
1491
+ if finished_func_addrs is None:
1492
+ finished_func_addrs = self._get_finished_functions()
1493
+
1494
+ for func_addr in finished_func_addrs:
1495
+ if func_addr in self._jobs_to_analyze_per_function:
1496
+ del self._jobs_to_analyze_per_function[func_addr]
1497
+
1498
+ def _make_completed_functions(self):
1499
+ """
1500
+ Fill in self._completed_functions list and clean up job manager.
1501
+
1502
+ :return: None
1503
+ """
1504
+
1505
+ finished = self._get_finished_functions()
1506
+ for func_addr in finished:
1507
+ if func_addr not in self._completed_functions:
1508
+ self._function_completed(func_addr)
1509
+ self._completed_functions.add(func_addr)
1510
+ self._cleanup_analysis_jobs(finished_func_addrs=finished)
1511
+
1512
+ #
1513
+ # Function identification and such
1514
+ #
1515
+
1516
+ def mark_function_alignments(self):
1517
+ """
1518
+ Find all potential function alignments and mark them.
1519
+
1520
+ Note that it is not always correct to simply remove them, because these functions may not be actual alignments
1521
+ but part of an actual function, and is incorrectly marked as an individual function because of failures in
1522
+ resolving indirect jumps. An example is in the test binary ``x86_64/dir_gcc_-O0`` 0x40541d (indirect jump at
1523
+ 0x4051b0). If the indirect jump cannot be correctly resolved, removing function 0x40541d will cause a missing
1524
+ label failure in reassembler.
1525
+
1526
+ :return: None
1527
+ """
1528
+
1529
+ # This function requires Capstone engine support
1530
+ if not self.project.arch.capstone_support:
1531
+ return
1532
+
1533
+ for func_addr in self.kb.functions.keys():
1534
+ function = self.kb.functions[func_addr]
1535
+ if function.is_simprocedure or function.is_syscall:
1536
+ continue
1537
+ if len(function.block_addrs_set) == 1:
1538
+ block = next((b for b in function.blocks), None)
1539
+ if block is None:
1540
+ continue
1541
+ if all(self._is_noop_insn(insn) for insn in block.capstone.insns):
1542
+ # all nops. mark this function as a function alignment
1543
+ l.debug("Function chunk %#x is probably used as a function alignment (all nops).", func_addr)
1544
+ self.kb.functions[func_addr].alignment = True
1545
+ continue
1546
+ node = function.get_node(block.addr)
1547
+ successors = list(function.graph.successors(node))
1548
+ if len(successors) == 1 and successors[0].addr == node.addr:
1549
+ # self loop. mark this function as a function alignment
1550
+ l.debug("Function chunk %#x is probably used as a function alignment (self-loop).", func_addr)
1551
+ self.kb.functions[func_addr].alignment = True
1552
+ continue
1553
+
1554
+ def make_functions(self):
1555
+ """
1556
+ Revisit the entire control flow graph, create Function instances accordingly, and correctly put blocks into
1557
+ each function.
1558
+
1559
+ Although Function objects are crated during the CFG recovery, they are neither sound nor accurate. With a
1560
+ pre-constructed CFG, this method rebuilds all functions bearing the following rules:
1561
+
1562
+ - A block may only belong to one function.
1563
+ - Small functions lying inside the startpoint and the endpoint of another function will be merged with the
1564
+ other function
1565
+ - Tail call optimizations are detected.
1566
+ - PLT stubs are aligned by 16.
1567
+
1568
+ :return: None
1569
+ """
1570
+
1571
+ # TODO: Is it required that PLT stubs are always aligned by 16? If so, on what architectures and platforms is it
1572
+ # TODO: enforced?
1573
+
1574
+ tmp_functions = self.kb.functions.copy()
1575
+
1576
+ for function in tmp_functions.values():
1577
+ function.mark_nonreturning_calls_endpoints()
1578
+ if function.returning is False:
1579
+ # remove all FakeRet edges that are related to this function
1580
+ func_node = self.model.get_any_node(function.addr)
1581
+ if func_node is not None:
1582
+ callsite_nodes = [
1583
+ src
1584
+ for src, _, data in self.graph.in_edges(func_node, data=True)
1585
+ if data.get("jumpkind", None) == "Ijk_Call"
1586
+ ]
1587
+ for callsite_node in callsite_nodes:
1588
+ for _, dst, data in list(self.graph.out_edges(callsite_node, data=True)):
1589
+ if data.get("jumpkind", None) == "Ijk_FakeRet":
1590
+ self.graph.remove_edge(callsite_node, dst)
1591
+
1592
+ # Clear old functions dict
1593
+ self.kb.functions.clear()
1594
+
1595
+ blockaddr_to_function = {}
1596
+ traversed_cfg_nodes = set()
1597
+
1598
+ function_nodes = set()
1599
+
1600
+ # Find nodes for beginnings of all functions
1601
+ for _, dst, data in self.graph.edges(data=True):
1602
+ jumpkind = data.get("jumpkind", "")
1603
+ if jumpkind == "Ijk_Call" or jumpkind.startswith("Ijk_Sys"):
1604
+ function_nodes.add(dst)
1605
+
1606
+ entry_node = self.model.get_any_node(self._binary.entry)
1607
+ if entry_node is not None:
1608
+ function_nodes.add(entry_node)
1609
+
1610
+ # aggressively remove and merge functions
1611
+ # For any function, if there is a call to it, it won't be removed
1612
+ called_function_addrs = {n.addr for n in function_nodes}
1613
+ # Any function addresses that appear as symbols won't be removed
1614
+ predetermined_function_addrs = called_function_addrs | self._function_addresses_from_symbols
1615
+
1616
+ removed_functions_a = self._process_irrational_functions(
1617
+ tmp_functions, predetermined_function_addrs, blockaddr_to_function
1618
+ )
1619
+ removed_functions_b, adjusted_cfgnodes = self._process_irrational_function_starts(
1620
+ tmp_functions, predetermined_function_addrs, blockaddr_to_function
1621
+ )
1622
+ self._process_jump_table_targeted_functions(
1623
+ tmp_functions,
1624
+ predetermined_function_addrs,
1625
+ blockaddr_to_function,
1626
+ )
1627
+ removed_functions = removed_functions_a | removed_functions_b
1628
+
1629
+ # Remove all nodes that are adjusted
1630
+ function_nodes.difference_update(adjusted_cfgnodes)
1631
+ for n in self.graph.nodes():
1632
+ if n.addr in tmp_functions or n.addr in removed_functions:
1633
+ function_nodes.add(n)
1634
+
1635
+ # traverse the graph starting from each node, not following call edges
1636
+ # it's important that we traverse all functions in order so that we have a greater chance to come across
1637
+ # rational functions before its irrational counterparts (e.g. due to failed jump table resolution)
1638
+
1639
+ min_stage_2_progress = 50.0
1640
+ max_stage_2_progress = 90.0
1641
+ nodes_count = len(function_nodes)
1642
+ for i, fn in enumerate(sorted(function_nodes, key=lambda n: n.addr)):
1643
+ if self._low_priority:
1644
+ self._release_gil(i, 800, 0.000001)
1645
+
1646
+ if self._show_progressbar or self._progress_callback:
1647
+ progress = min_stage_2_progress + (max_stage_2_progress - min_stage_2_progress) * (
1648
+ i * 1.0 / nodes_count
1649
+ )
1650
+ self._update_progress(progress)
1651
+
1652
+ self._graph_bfs_custom(
1653
+ self.graph,
1654
+ [fn],
1655
+ self._graph_traversal_handler,
1656
+ blockaddr_to_function,
1657
+ tmp_functions,
1658
+ traversed_cfg_nodes,
1659
+ )
1660
+
1661
+ # Don't forget those small function chunks that are not called by anything.
1662
+ # There might be references to them from data, or simply references that we cannot find via static analysis
1663
+
1664
+ secondary_function_nodes = set()
1665
+ # add all function chunks ("functions" that are not called from anywhere)
1666
+ for func_addr in tmp_functions:
1667
+ node = self.model.get_any_node(func_addr)
1668
+ if node is None:
1669
+ continue
1670
+ if node.addr not in blockaddr_to_function:
1671
+ secondary_function_nodes.add(node)
1672
+
1673
+ missing_cfg_nodes = set(self.graph.nodes()) - traversed_cfg_nodes
1674
+ missing_cfg_nodes = {node for node in missing_cfg_nodes if node.function_address is not None}
1675
+ if missing_cfg_nodes:
1676
+ l.debug("%d CFGNodes are missing in the first traversal.", len(missing_cfg_nodes))
1677
+ secondary_function_nodes |= missing_cfg_nodes
1678
+
1679
+ min_stage_3_progress = 90.0
1680
+ max_stage_3_progress = 99.9
1681
+
1682
+ nodes_count = len(secondary_function_nodes)
1683
+ for i, fn in enumerate(sorted(secondary_function_nodes, key=lambda n: n.addr)):
1684
+ if self._show_progressbar or self._progress_callback:
1685
+ progress = min_stage_3_progress + (max_stage_3_progress - min_stage_3_progress) * (
1686
+ i * 1.0 / nodes_count
1687
+ )
1688
+ self._update_progress(progress)
1689
+
1690
+ self._graph_bfs_custom(
1691
+ self.graph, [fn], self._graph_traversal_handler, blockaddr_to_function, tmp_functions
1692
+ )
1693
+
1694
+ to_remove = set()
1695
+
1696
+ # Remove all stubs after PLT entries
1697
+ if not is_arm_arch(self.project.arch):
1698
+ to_remove |= self._remove_dummy_plt_stubs(self.kb.functions)
1699
+
1700
+ # remove empty functions
1701
+ for func in self.kb.functions.values():
1702
+ if func.startpoint is None:
1703
+ to_remove.add(func.addr)
1704
+
1705
+ for addr in to_remove:
1706
+ del self.kb.functions[addr]
1707
+
1708
+ # Update CFGNode.function_address
1709
+ for node in self._nodes.values():
1710
+ if node.addr in blockaddr_to_function:
1711
+ node.function_address = blockaddr_to_function[node.addr].addr
1712
+
1713
+ # Update function.info
1714
+ for func in self.kb.functions.values():
1715
+ if func.addr in tmp_functions:
1716
+ func.info = tmp_functions[func.addr].info
1717
+
1718
+ def _remove_dummy_plt_stubs(self, functions):
1719
+ def _is_function_a_plt_stub(arch_, func):
1720
+ if len(func.block_addrs_set) != 1:
1721
+ # multiple blocks? no idea what this is...
1722
+ return False
1723
+ block = next(func.blocks)
1724
+ if self._is_noop_block(arch_, block):
1725
+ # alignments
1726
+ return False
1727
+ if (
1728
+ arch_.name in {"X86", "AMD64"}
1729
+ and len(block.vex.instruction_addresses) == 2
1730
+ and block.vex.jumpkind == "Ijk_Boring"
1731
+ ):
1732
+ # push ordinal; jump _resolve
1733
+ return False
1734
+ # TODO: We may want to add support for filtering dummy PLT stubs for other architectures, but I haven't
1735
+ # TODO: seen any need for those.
1736
+ return True
1737
+
1738
+ to_remove = set()
1739
+
1740
+ met_plts = False
1741
+ non_plt_funcs = 0
1742
+ sorted_func_addrs = sorted(functions.keys())
1743
+ arch = self.project.arch
1744
+
1745
+ # we assume all PLT entries are all located at the same region. the moment we come across the end of it, we
1746
+ # stop looping.
1747
+ for fn_addr in sorted_func_addrs:
1748
+ fn = functions.get_by_addr(fn_addr)
1749
+ addr = fn.addr - (fn.addr % 16)
1750
+ if addr != fn.addr:
1751
+ if addr in functions and functions[addr].is_plt and not _is_function_a_plt_stub(arch, fn):
1752
+ to_remove.add(fn.addr)
1753
+ continue
1754
+
1755
+ if fn.is_plt:
1756
+ met_plts = True
1757
+ non_plt_funcs = 0
1758
+ if met_plts and not fn.is_plt:
1759
+ non_plt_funcs += 1
1760
+ if non_plt_funcs >= 2:
1761
+ break
1762
+
1763
+ return to_remove
1764
+
1765
+ def _process_irrational_functions(self, functions, predetermined_function_addrs, blockaddr_to_function):
1766
+ """
1767
+ When force_complete_scan is enabled, for unresolveable indirect jumps, angr will find jump targets and mark
1768
+ them as individual functions. For example, usually the following pattern is seen:
1769
+
1770
+ sub_0x400010:
1771
+ push ebp
1772
+ mov esp, ebp
1773
+ ...
1774
+ cmp eax, 10
1775
+ ja end
1776
+ mov eax, jumptable[eax]
1777
+ jmp eax
1778
+
1779
+ sub_0x400080:
1780
+ # do something here
1781
+ jmp end
1782
+
1783
+ end (0x400e00):
1784
+ pop ebp
1785
+ ret
1786
+
1787
+ In the example above, `process_irrational_functions` will remove function 0x400080, and merge it with function
1788
+ 0x400010.
1789
+
1790
+ :param angr.knowledge_plugins.FunctionManager functions: all functions that angr recovers, including those ones
1791
+ that are misidentified as functions.
1792
+ :param dict blockaddr_to_function: A mapping between block addresses and Function instances.
1793
+ :return: A set of addresses of all removed functions
1794
+ :rtype: set
1795
+ """
1796
+
1797
+ functions_to_remove = {}
1798
+
1799
+ all_func_addrs = sorted(set(functions.keys()))
1800
+
1801
+ for func_pos, (func_addr, function) in enumerate(functions.items()):
1802
+ if func_addr in functions_to_remove:
1803
+ continue
1804
+
1805
+ # check all blocks and see if any block ends with an indirect jump and is not resolved
1806
+ has_unresolved_jumps = False
1807
+ # the functions to merge with must be locating between the unresolved basic block address and the endpoint
1808
+ # of the current function
1809
+ max_unresolved_jump_addr = 0
1810
+ for block_addr in function.block_addrs_set:
1811
+ if (
1812
+ block_addr in self.indirect_jumps
1813
+ and self.indirect_jumps[block_addr].jumpkind == "Ijk_Boring"
1814
+ and not self.indirect_jumps[block_addr].resolved_targets
1815
+ ):
1816
+ # it's not resolved
1817
+ # we should also make sure it's a jump, not a call
1818
+ has_unresolved_jumps = True
1819
+ max_unresolved_jump_addr = max(max_unresolved_jump_addr, block_addr)
1820
+
1821
+ if not has_unresolved_jumps:
1822
+ continue
1823
+
1824
+ if function.startpoint is None:
1825
+ continue
1826
+
1827
+ startpoint_addr = function.startpoint.addr
1828
+ if not function.endpoints:
1829
+ # Function should have at least one endpoint
1830
+ continue
1831
+ endpoint_addr = max(a.addr for a in function.endpoints)
1832
+ the_endpoint = next(a for a in function.endpoints if a.addr == endpoint_addr)
1833
+ endpoint_addr += the_endpoint.size
1834
+
1835
+ # sanity check: startpoint of the function should be greater than its endpoint
1836
+ if startpoint_addr >= endpoint_addr:
1837
+ continue
1838
+ if max_unresolved_jump_addr <= startpoint_addr or max_unresolved_jump_addr >= endpoint_addr:
1839
+ continue
1840
+
1841
+ # scan forward from the endpoint to include any function-tail jumps
1842
+ # Here is an example:
1843
+ # loc_8049562:
1844
+ # mov eax, ebp
1845
+ # add esp, 3ch
1846
+ # ...
1847
+ # ret
1848
+ # loc_804956c:
1849
+ # mov ebp, 3
1850
+ # jmp loc_8049562
1851
+ # loc_8049573:
1852
+ # mov ebp, 4
1853
+ # jmp loc_8049562
1854
+ #
1855
+ last_addr = endpoint_addr
1856
+ while True:
1857
+ try:
1858
+ # do not follow hooked addresses (such as SimProcedures)
1859
+ if self.project.is_hooked(last_addr):
1860
+ break
1861
+
1862
+ next_block = self._lift(last_addr)
1863
+ next_block_irsb = next_block.vex_nostmt
1864
+ if next_block_irsb.jumpkind not in ("Ijk_Boring", "Ijk_InvalICache"):
1865
+ break
1866
+ if not isinstance(next_block_irsb.next, pyvex.IRExpr.Const):
1867
+ break
1868
+ suc_addr = next_block_irsb.next.con.value
1869
+ if (
1870
+ max(startpoint_addr, the_endpoint.addr - 0x40)
1871
+ <= suc_addr
1872
+ < the_endpoint.addr + the_endpoint.size
1873
+ ):
1874
+ # increment the endpoint_addr
1875
+ endpoint_addr = next_block.addr + next_block.size
1876
+ else:
1877
+ break
1878
+
1879
+ last_addr = next_block.addr + next_block.size
1880
+
1881
+ except (SimTranslationError, SimMemoryError, SimIRSBError, SimEngineError):
1882
+ break
1883
+
1884
+ # find all functions that are between [ startpoint, endpoint ]
1885
+
1886
+ should_merge = True
1887
+ functions_to_merge = set()
1888
+ i = func_pos + 1
1889
+ while i < len(all_func_addrs):
1890
+ f_addr = all_func_addrs[i]
1891
+ i += 1
1892
+ f = functions[f_addr]
1893
+ if f_addr == func_addr:
1894
+ continue
1895
+ if max_unresolved_jump_addr < f_addr < endpoint_addr and all(
1896
+ max_unresolved_jump_addr < b_addr < endpoint_addr for b_addr in f.block_addrs
1897
+ ):
1898
+ if f_addr in functions_to_remove:
1899
+ # this function has already been merged with other functions before... it cannot be merged with
1900
+ # this function anymore
1901
+ should_merge = False
1902
+ break
1903
+ if f_addr in predetermined_function_addrs:
1904
+ # this function is a legit one. it shouldn't be removed/merged
1905
+ should_merge = False
1906
+ break
1907
+ functions_to_merge.add(f_addr)
1908
+
1909
+ if not should_merge:
1910
+ # we shouldn't merge...
1911
+ continue
1912
+
1913
+ for f_addr in functions_to_merge:
1914
+ functions_to_remove[f_addr] = func_addr
1915
+
1916
+ # merge all functions
1917
+ for to_remove, merge_with in functions_to_remove.items():
1918
+ func_merge_with = self._addr_to_function(merge_with, blockaddr_to_function, functions)
1919
+
1920
+ for block_addr in functions[to_remove].block_addrs:
1921
+ blockaddr_to_function[block_addr] = func_merge_with
1922
+
1923
+ del functions[to_remove]
1924
+
1925
+ return set(functions_to_remove.keys())
1926
+
1927
+ def _process_irrational_function_starts(self, functions, predetermined_function_addrs, blockaddr_to_function):
1928
+ """
1929
+ Functions that are identified via function prologues can be starting after the actual beginning of the function.
1930
+ For example, the following function (with an incorrect start) might exist after a CFG recovery:
1931
+
1932
+ sub_8049f70:
1933
+ push esi
1934
+
1935
+ sub_8049f71:
1936
+ sub esp, 0A8h
1937
+ mov esi, [esp+0ACh+arg_0]
1938
+ mov [esp+0ACh+var_88], 0
1939
+
1940
+ If the following conditions are met, we will remove the second function and merge it into the first function:
1941
+ - The second function is not called by other code.
1942
+ - The first function has only one jumpout site, which points to the second function.
1943
+
1944
+ :param FunctionManager functions: All functions that angr recovers.
1945
+ :return: A set of addresses of all removed functions.
1946
+ :rtype: set
1947
+ """
1948
+
1949
+ addrs = sorted(
1950
+ k for k in functions.keys() if not self.project.is_hooked(k) and not self.project.simos.is_syscall_addr(k)
1951
+ )
1952
+ functions_to_remove = set()
1953
+ adjusted_cfgnodes = set()
1954
+
1955
+ for addr_0, addr_1 in zip(addrs[:-1], addrs[1:]):
1956
+ if addr_1 in predetermined_function_addrs:
1957
+ continue
1958
+ if addr_0 in functions_to_remove:
1959
+ continue
1960
+
1961
+ func_0 = functions[addr_0]
1962
+
1963
+ if len(func_0.block_addrs_set) >= 1:
1964
+ if len(func_0.jumpout_sites) != 1:
1965
+ continue
1966
+ block_node = func_0.jumpout_sites[0]
1967
+ if block_node is None:
1968
+ continue
1969
+ if block_node.size == 0:
1970
+ # skip empty blocks (that are usually caused by lifting failures)
1971
+ continue
1972
+ block = func_0.get_block(block_node.addr, block_node.size)
1973
+ if block.vex.jumpkind not in ("Ijk_Boring", "Ijk_InvalICache"):
1974
+ continue
1975
+ # Skip alignment blocks
1976
+ if self._is_noop_block(self.project.arch, block):
1977
+ continue
1978
+
1979
+ # does the first block transition to the next function?
1980
+ transition_found = False
1981
+ out_edges = list(func_0.transition_graph.out_edges(block_node, data=True))
1982
+ for _, dst_node, data in out_edges:
1983
+ if (
1984
+ dst_node.addr == addr_1
1985
+ and data.get("type", None) == "transition"
1986
+ and data.get("outside", False) is True
1987
+ ):
1988
+ transition_found = True
1989
+ break
1990
+
1991
+ if not transition_found:
1992
+ continue
1993
+
1994
+ cfgnode_0 = self.model.get_any_node(block_node.addr)
1995
+ cfgnode_1 = self.model.get_any_node(addr_1)
1996
+
1997
+ if cfgnode_0 is None or cfgnode_1 is None:
1998
+ continue
1999
+
2000
+ # who's jumping to or calling cfgnode_1?
2001
+ cfgnode_1_preds = self.model.get_predecessors_and_jumpkinds(cfgnode_1, excluding_fakeret=True)
2002
+ func_1 = functions[addr_1]
2003
+ abort = False
2004
+ for pred, jumpkind in cfgnode_1_preds:
2005
+ if pred.addr in func_0.block_addrs_set and jumpkind == "Ijk_Boring":
2006
+ # this is the transition from function 0
2007
+ continue
2008
+ if pred.addr in func_1.block_addrs_set:
2009
+ # this is a transition from function 1 itself
2010
+ continue
2011
+ # found an unexpected edge. give up
2012
+ abort = True
2013
+ break
2014
+ if abort:
2015
+ continue
2016
+
2017
+ # Merge block addr_0 and block addr_1
2018
+ l.debug("Merging function %#x into %#x.", addr_1, addr_0)
2019
+
2020
+ cfgnode_1_merged = False
2021
+ # we only merge two CFG nodes if the first one does not end with a branch instruction
2022
+ if (
2023
+ len(func_0.block_addrs_set) == 1
2024
+ and len(out_edges) == 1
2025
+ and out_edges[0][0].addr == cfgnode_0.addr
2026
+ and out_edges[0][0].size == cfgnode_0.size
2027
+ and self.project.factory.block(cfgnode_0.addr, strict_block_end=True).size > cfgnode_0.size
2028
+ ):
2029
+ cfgnode_1_merged = True
2030
+ self._merge_cfgnodes(cfgnode_0, cfgnode_1)
2031
+ adjusted_cfgnodes.add(cfgnode_0)
2032
+ adjusted_cfgnodes.add(cfgnode_1)
2033
+
2034
+ # Merge it
2035
+ func_1 = functions[addr_1]
2036
+ for block_addr in func_1.block_addrs:
2037
+ if block_addr == addr_1 and cfgnode_1_merged:
2038
+ # Skip addr_1 (since it has been merged to the preceding block)
2039
+ continue
2040
+ merge_with = self._addr_to_function(addr_0, blockaddr_to_function, functions)
2041
+ blockaddr_to_function[block_addr] = merge_with
2042
+
2043
+ functions_to_remove.add(addr_1)
2044
+
2045
+ for to_remove in functions_to_remove:
2046
+ del functions[to_remove]
2047
+
2048
+ return functions_to_remove, adjusted_cfgnodes
2049
+
2050
+ def _process_jump_table_targeted_functions(
2051
+ self, functions, predetermined_function_addrs, blockaddr_to_function
2052
+ ) -> set[int]:
2053
+ """
2054
+ Sometimes compilers will optimize "cold" code regions, make them separate functions, mark them as cold, which
2055
+ conflicts with how angr handles jumps to these functions (because they weren't functions to start with). Here
2056
+ is an example (in function version_etc_arn() from gllib)::
2057
+
2058
+ switch (n_authors) {
2059
+ case 0:
2060
+ abort();
2061
+ case 1:
2062
+ ...
2063
+ }
2064
+
2065
+ GCC may decide to move the `abort();` block under case 0 into a separate function (usually named
2066
+ "version_etc_arn_cold") and mark it as "cold." When loading function hints from eh frame is enabled, this
2067
+ function will be identified, and the recovered switch-case structure will have a jump to a function. It's
2068
+ usually not a problem until we need to decompile this function, where (at least for now) angr decompiler
2069
+ requires all switch-case entry blocks must belong to the same function.
2070
+
2071
+ The temporary solution is identifying functions that (a) have no call predecessors, and (b) are used as
2072
+ jump targets for identified jump tables. Remove these functions so that they can be treated as part of the
2073
+ source function where the corresponding jump table belongs.
2074
+ """
2075
+
2076
+ jumptable_entries: set[int] = set()
2077
+ for jt in self.model.jump_tables.values():
2078
+ assert jt.jumptable_entries is not None
2079
+ jumptable_entries |= set(jt.jumptable_entries)
2080
+
2081
+ if not jumptable_entries:
2082
+ return set()
2083
+
2084
+ functions_to_remove = set()
2085
+
2086
+ for func_addr in functions.keys():
2087
+ if func_addr in predetermined_function_addrs:
2088
+ continue
2089
+ if func_addr in jumptable_entries:
2090
+ # is there any call edge pointing to it?
2091
+ func_node = self.get_any_node(func_addr)
2092
+ if func_node is not None:
2093
+ in_edges = self.graph.in_edges(func_node, data=True)
2094
+ has_transition_pred = None
2095
+ has_non_transition_pred = None
2096
+ for _, _, data in in_edges:
2097
+ if data.get("jumpkind", None) == "Ijk_Boring":
2098
+ has_transition_pred = True
2099
+ else:
2100
+ has_non_transition_pred = True
2101
+ if has_transition_pred is True and not has_non_transition_pred:
2102
+ # all predecessors are transition-only
2103
+ # remove this function
2104
+ functions_to_remove.add(func_addr)
2105
+
2106
+ for to_remove in functions_to_remove:
2107
+ del functions[to_remove]
2108
+ if to_remove in blockaddr_to_function:
2109
+ del blockaddr_to_function[to_remove]
2110
+
2111
+ return functions_to_remove
2112
+
2113
+ def _addr_to_function(self, addr, blockaddr_to_function, known_functions):
2114
+ """
2115
+ Convert an address to a Function object, and store the mapping in a dict. If the block is known to be part of a
2116
+ function, just return that function.
2117
+
2118
+ :param int addr: Address to convert
2119
+ :param dict blockaddr_to_function: A mapping between block addresses to Function instances.
2120
+ :param angr.knowledge_plugins.FunctionManager known_functions: Recovered functions.
2121
+ :return: a Function object
2122
+ :rtype: angr.knowledge.Function
2123
+ """
2124
+
2125
+ if addr in blockaddr_to_function:
2126
+ f = blockaddr_to_function[addr]
2127
+ else:
2128
+ is_syscall = self.project.simos.is_syscall_addr(addr)
2129
+
2130
+ n = self.model.get_any_node(addr, is_syscall=is_syscall)
2131
+ if n is None:
2132
+ node = addr
2133
+ else:
2134
+ node = self._to_snippet(n)
2135
+
2136
+ if isinstance(addr, SootAddressDescriptor):
2137
+ addr = addr.method
2138
+
2139
+ self.kb.functions._add_node(addr, node, syscall=is_syscall)
2140
+ f = self.kb.functions.function(addr=addr)
2141
+ assert f is not None
2142
+
2143
+ blockaddr_to_function[addr] = f
2144
+
2145
+ function_is_returning = False
2146
+ if addr in known_functions:
2147
+ if known_functions.function(addr).returning:
2148
+ f.returning = True
2149
+ function_is_returning = True
2150
+
2151
+ if not function_is_returning:
2152
+ # We will rerun function feature analysis on this function later. Add it to
2153
+ # self._updated_nonreturning_functions so it can be picked up by function feature analysis later.
2154
+ if self._updated_nonreturning_functions is not None:
2155
+ self._updated_nonreturning_functions.add(addr)
2156
+
2157
+ return f
2158
+
2159
+ def _is_tail_call_optimization(
2160
+ self,
2161
+ g: "networkx.DiGraph[CFGNode]",
2162
+ src_addr,
2163
+ dst_addr,
2164
+ src_function,
2165
+ all_edges: list[tuple[CFGNode, CFGNode, Any]],
2166
+ known_functions,
2167
+ blockaddr_to_function,
2168
+ ):
2169
+ """
2170
+ If source and destination belong to the same function, and the following criteria apply:
2171
+ - source node has only one default exit
2172
+ - destination is not one of the known functions
2173
+ - destination does not belong to another function, or destination belongs to the same function that
2174
+ source belongs to
2175
+ - at the end of the block, the SP offset is 0
2176
+ - for all other edges that are pointing to the destination node, their source nodes must only have one default
2177
+ exit, too
2178
+
2179
+ :return: True if it is a tail-call optimization. False otherwise.
2180
+ :rtype: bool
2181
+ """
2182
+
2183
+ def _has_more_than_one_exit(node_):
2184
+ # Do not consider FakeRets as counting as multiple exits here.
2185
+ out_edges = [e for e in g.out_edges(node_) if g.get_edge_data(*e)["jumpkind"] != "Ijk_FakeRet"]
2186
+ return len(out_edges) > 1
2187
+
2188
+ if len(src_function.block_addrs_set) > 10:
2189
+ # ignore functions unless they are extremely small
2190
+ return False
2191
+
2192
+ if len(all_edges) == 1 and dst_addr != src_addr:
2193
+ the_edge = next(iter(all_edges))
2194
+ _, dst, data = the_edge
2195
+ if data.get("stmt_idx", None) != DEFAULT_STATEMENT:
2196
+ return False
2197
+
2198
+ # relift the source node to make sure it's not a fall-through target
2199
+ full_src_node = self.project.factory.block(src_addr)
2200
+ if full_src_node.size >= VEX_IRSB_MAX_SIZE or full_src_node.instructions >= VEX_IRSB_MAX_INST:
2201
+ # we are probably hitting the max-block limit in VEX
2202
+ return False
2203
+ if full_src_node.addr <= dst_addr < full_src_node.addr + full_src_node.size:
2204
+ return False
2205
+
2206
+ dst_in_edges = g.in_edges(dst, data=True)
2207
+ if len(dst_in_edges) > 1:
2208
+ # there are other edges going to the destination node. check all edges to make sure all source nodes
2209
+ # only have one default exit
2210
+ if any(data.get("stmt_idx", None) != DEFAULT_STATEMENT for _, _, data in dst_in_edges):
2211
+ # some nodes are jumping to the destination node via non-default edges. skip.
2212
+ return False
2213
+ if any(_has_more_than_one_exit(src_) for src_, _, _ in dst_in_edges):
2214
+ # at least one source node has more than just the default exit. skip.
2215
+ return False
2216
+
2217
+ candidate = False
2218
+ if dst_addr in known_functions:
2219
+ # dst_addr cannot be the same as src_function.addr. Pass
2220
+ pass
2221
+ elif dst_addr in blockaddr_to_function:
2222
+ # it seems that we already know where this function should belong to. Pass.
2223
+ dst_func = blockaddr_to_function[dst_addr]
2224
+ if dst_func is src_function:
2225
+ # they belong to the same function right now, but they'd better not
2226
+ candidate = True
2227
+ # treat it as a tail-call optimization
2228
+ else:
2229
+ # we don't know where it belongs to
2230
+ # treat it as a tail-call optimization
2231
+ candidate = True
2232
+
2233
+ if candidate:
2234
+ regs = {self.project.arch.sp_offset}
2235
+ if hasattr(self.project.arch, "bp_offset") and self.project.arch.bp_offset is not None:
2236
+ regs.add(self.project.arch.bp_offset)
2237
+ sptracker = self.project.analyses[StackPointerTracker].prep()(
2238
+ src_function, regs, track_memory=self._sp_tracking_track_memory
2239
+ )
2240
+ sp_delta = sptracker.offset_after_block(src_addr, self.project.arch.sp_offset)
2241
+ if sp_delta == 0:
2242
+ return True
2243
+
2244
+ return False
2245
+
2246
+ def _graph_bfs_custom(self, g, starts, callback, blockaddr_to_function, known_functions, traversed_cfg_nodes=None):
2247
+ """
2248
+ A customized control flow graph BFS implementation with the following rules:
2249
+ - Call edges are not followed.
2250
+ - Syscall edges are not followed.
2251
+
2252
+ :param networkx.DiGraph g: The graph.
2253
+ :param list starts: A collection of beginning nodes to start graph traversal.
2254
+ :param func callback: Callback function for each edge and node.
2255
+ :param dict blockaddr_to_function: A mapping between block addresses to Function instances.
2256
+ :param angr.knowledge_plugins.FunctionManager known_functions: Already recovered functions.
2257
+ :param set traversed_cfg_nodes: A set of CFGNodes that are traversed before.
2258
+ :return: None
2259
+ """
2260
+
2261
+ stack = OrderedSet(starts)
2262
+ traversed = set() if traversed_cfg_nodes is None else traversed_cfg_nodes
2263
+
2264
+ while stack:
2265
+ n: CFGNode = stack.pop(last=False)
2266
+
2267
+ if n in traversed:
2268
+ continue
2269
+
2270
+ traversed.add(n)
2271
+
2272
+ if n.has_return:
2273
+ callback(g, n, None, {"jumpkind": "Ijk_Ret"}, blockaddr_to_function, known_functions, None)
2274
+ # NOTE: A block that has_return CAN have successors that aren't the return.
2275
+ # This is particularly the case for ARM conditional instructions. Yes, conditional rets are a thing.
2276
+
2277
+ if g.out_degree(n) == 0:
2278
+ # it's a single node
2279
+ callback(g, n, None, None, blockaddr_to_function, known_functions, None)
2280
+
2281
+ else:
2282
+ all_out_edges = g.out_edges(n, data=True)
2283
+ for src, dst, data in all_out_edges:
2284
+ callback(g, src, dst, data, blockaddr_to_function, known_functions, all_out_edges)
2285
+
2286
+ jumpkind = data.get("jumpkind", "")
2287
+ if not (jumpkind in ("Ijk_Call", "Ijk_Ret") or jumpkind.startswith("Ijk_Sys")):
2288
+ if dst not in stack and dst not in traversed:
2289
+ stack.add(dst)
2290
+
2291
+ def _graph_traversal_handler(self, g, src, dst, data, blockaddr_to_function, known_functions, all_edges):
2292
+ """
2293
+ Graph traversal handler. It takes in a node or an edge, and create new functions or add nodes to existing
2294
+ functions accordingly. Oh, it also create edges on the transition map of functions.
2295
+
2296
+ :param g: The control flow graph that is currently being traversed.
2297
+ :param CFGNode src: Beginning of the edge, or a single node when dst is None.
2298
+ :param CFGNode dst: Destination of the edge. For processing a single node, `dst` is None.
2299
+ :param dict data: Edge data in the CFG. 'jumpkind' should be there if it's not None.
2300
+ :param dict blockaddr_to_function: A mapping between block addresses to Function instances.
2301
+ :param angr.knowledge_plugins.FunctionManager known_functions: Already recovered functions.
2302
+ :param list or None all_edges: All edges going out from src.
2303
+ :return: None
2304
+ """
2305
+
2306
+ src_addr = src.addr
2307
+ src_function = self._addr_to_function(src_addr, blockaddr_to_function, known_functions)
2308
+
2309
+ if src_addr not in src_function.block_addrs_set:
2310
+ n = self.model.get_any_node(src_addr)
2311
+ if n is None:
2312
+ node = src_addr
2313
+ else:
2314
+ node = self._to_snippet(n)
2315
+ self.kb.functions._add_node(src_function.addr, node)
2316
+
2317
+ if data is None:
2318
+ # it's a single node only
2319
+ return
2320
+
2321
+ jumpkind = data["jumpkind"]
2322
+
2323
+ if jumpkind == "Ijk_Ret":
2324
+ n = self.model.get_any_node(src_addr)
2325
+ if n is None:
2326
+ from_node = src_addr
2327
+ else:
2328
+ from_node = self._to_snippet(n)
2329
+ self.kb.functions._add_return_from(src_function.addr, from_node, None)
2330
+
2331
+ if dst is None:
2332
+ return
2333
+
2334
+ dst_addr = dst.addr
2335
+
2336
+ # get instruction address and statement index
2337
+ ins_addr = data.get("ins_addr", None)
2338
+ stmt_idx = data.get("stmt_idx", None)
2339
+
2340
+ if jumpkind == "Ijk_Call" or jumpkind.startswith("Ijk_Sys"):
2341
+ is_syscall = jumpkind.startswith("Ijk_Sys")
2342
+
2343
+ # It must be calling a function
2344
+ dst_function = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
2345
+
2346
+ n = self.model.get_any_node(src_addr)
2347
+ if n is None:
2348
+ src_snippet = self._to_snippet(addr=src_addr, base_state=self._base_state)
2349
+ else:
2350
+ src_snippet = self._to_snippet(cfg_node=n)
2351
+
2352
+ # HACK: FIXME: We need a better way of representing unresolved calls and whether they return.
2353
+ # For now, assume UnresolvedTarget returns if we're calling to it
2354
+
2355
+ # If the function doesn't return, don't add a fakeret!
2356
+ if not all_edges or (dst_function.returning is False and not dst_function.name == "UnresolvableCallTarget"):
2357
+ fakeret_node = None
2358
+ else:
2359
+ fakeret_node = self._one_fakeret_node(all_edges)
2360
+
2361
+ if fakeret_node is None:
2362
+ fakeret_snippet = None
2363
+ else:
2364
+ fakeret_snippet = self._to_snippet(cfg_node=fakeret_node)
2365
+
2366
+ if isinstance(dst_addr, SootAddressDescriptor):
2367
+ dst_addr = dst_addr.method
2368
+
2369
+ self.kb.functions._add_call_to(
2370
+ src_function.addr,
2371
+ src_snippet,
2372
+ dst_addr,
2373
+ fakeret_snippet,
2374
+ syscall=is_syscall,
2375
+ ins_addr=ins_addr,
2376
+ stmt_idx=stmt_idx,
2377
+ )
2378
+
2379
+ if dst_function.returning and fakeret_node is not None:
2380
+ returning_target = src.addr + src.size
2381
+ if returning_target not in blockaddr_to_function:
2382
+ if returning_target not in known_functions:
2383
+ blockaddr_to_function[returning_target] = src_function
2384
+ else:
2385
+ self._addr_to_function(returning_target, blockaddr_to_function, known_functions)
2386
+
2387
+ to_outside = blockaddr_to_function[returning_target] is not src_function
2388
+
2389
+ n = self.model.get_any_node(returning_target)
2390
+ if n is None:
2391
+ try:
2392
+ returning_snippet = self._to_snippet(addr=returning_target, base_state=self._base_state)
2393
+ except SimEngineError:
2394
+ # it may not exist
2395
+ returning_snippet = None
2396
+ else:
2397
+ returning_snippet = self._to_snippet(cfg_node=n)
2398
+
2399
+ if returning_snippet is not None:
2400
+ self.kb.functions._add_fakeret_to(
2401
+ src_function.addr, src_snippet, returning_snippet, confirmed=True, to_outside=to_outside
2402
+ )
2403
+
2404
+ elif jumpkind in ("Ijk_Boring", "Ijk_InvalICache", "Ijk_Exception"):
2405
+ # convert src_addr and dst_addr to CodeNodes
2406
+ n = self.model.get_any_node(src_addr)
2407
+ if n is None:
2408
+ src_node = src_addr
2409
+ else:
2410
+ src_node = self._to_snippet(cfg_node=n)
2411
+
2412
+ n = self.model.get_any_node(dst_addr)
2413
+ if n is None:
2414
+ dst_node = dst_addr
2415
+ else:
2416
+ dst_node = self._to_snippet(cfg_node=n)
2417
+
2418
+ if self._skip_unmapped_addrs:
2419
+ # pre-check: if source and destination do not belong to the same section, it must be jumping to another
2420
+ # function
2421
+ belong_to_same_section = self._addrs_belong_to_same_section(src_addr, dst_addr)
2422
+ if not belong_to_same_section:
2423
+ _ = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
2424
+
2425
+ if self._detect_tail_calls:
2426
+ if self._is_tail_call_optimization(
2427
+ g, src_addr, dst_addr, src_function, all_edges, known_functions, blockaddr_to_function
2428
+ ):
2429
+ l.debug("Possible tail-call optimization detected at function %#x.", dst_addr)
2430
+ # it's (probably) a tail-call optimization. we should make the destination node a new function
2431
+ # instead.
2432
+ blockaddr_to_function.pop(dst_addr, None)
2433
+ _ = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
2434
+ self.kb.functions._add_outside_transition_to(
2435
+ src_function.addr, src_node, dst_node, to_function_addr=dst_addr
2436
+ )
2437
+ self._tail_calls.add(dst_addr)
2438
+
2439
+ # is it a jump to another function?
2440
+ if isinstance(dst_addr, SootAddressDescriptor):
2441
+ is_known_function_addr = dst_addr.method in known_functions and dst_addr.method.addr == dst_addr
2442
+ else:
2443
+ is_known_function_addr = dst_addr in known_functions
2444
+
2445
+ if (is_known_function_addr and dst_addr != src_function.addr) or (
2446
+ dst_addr in blockaddr_to_function and blockaddr_to_function[dst_addr] is not src_function
2447
+ ):
2448
+ # yes it is
2449
+ dst_function_addr = (
2450
+ blockaddr_to_function[dst_addr].addr if dst_addr in blockaddr_to_function else dst_addr
2451
+ )
2452
+
2453
+ self.kb.functions._add_outside_transition_to(
2454
+ src_function.addr,
2455
+ src_node,
2456
+ dst_node,
2457
+ ins_addr=ins_addr,
2458
+ stmt_idx=stmt_idx,
2459
+ to_function_addr=dst_function_addr,
2460
+ is_exception=jumpkind == "Ijk_Exception",
2461
+ )
2462
+
2463
+ _ = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
2464
+ else:
2465
+ # no it's not
2466
+ # add the transition code
2467
+
2468
+ if dst_addr not in blockaddr_to_function:
2469
+ blockaddr_to_function[dst_addr] = src_function
2470
+
2471
+ self.kb.functions._add_transition_to(
2472
+ src_function.addr,
2473
+ src_node,
2474
+ dst_node,
2475
+ ins_addr=ins_addr,
2476
+ stmt_idx=stmt_idx,
2477
+ is_exception=jumpkind == "Ijk_Exception",
2478
+ )
2479
+
2480
+ elif jumpkind == "Ijk_FakeRet":
2481
+ # convert src_addr and dst_addr to CodeNodes
2482
+ n = self.model.get_any_node(src_addr)
2483
+ if n is None:
2484
+ src_node = src_addr
2485
+ else:
2486
+ src_node = self._to_snippet(n)
2487
+
2488
+ n = self.model.get_any_node(dst_addr)
2489
+ if n is None:
2490
+ dst_node = dst_addr
2491
+ else:
2492
+ dst_node = self._to_snippet(n)
2493
+
2494
+ if dst_addr not in blockaddr_to_function:
2495
+ if isinstance(dst_addr, SootAddressDescriptor):
2496
+ if dst_addr.method not in known_functions:
2497
+ blockaddr_to_function[dst_addr] = src_function
2498
+ target_function = src_function
2499
+ else:
2500
+ target_function = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
2501
+ else:
2502
+ if dst_addr not in known_functions:
2503
+ blockaddr_to_function[dst_addr] = src_function
2504
+ target_function = src_function
2505
+ else:
2506
+ target_function = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
2507
+ else:
2508
+ target_function = blockaddr_to_function[dst_addr]
2509
+
2510
+ # Figure out if the function called (not the function returned to) returns.
2511
+ # We may have determined that this does not happen, since the time this path
2512
+ # was scheduled for exploration
2513
+ called_function = None
2514
+ called_function_addr = None
2515
+ # Try to find the call that this fakeret goes with
2516
+ for _, d, e in all_edges:
2517
+ if e["jumpkind"] == "Ijk_Call":
2518
+ if d.addr in blockaddr_to_function:
2519
+ called_function = blockaddr_to_function[d.addr]
2520
+ called_function_addr = d.addr
2521
+ break
2522
+ # We may have since figured out that the called function doesn't ret.
2523
+ # It's important to assume that all unresolved targets do return
2524
+ if called_function is not None and called_function.returning is False:
2525
+ return
2526
+
2527
+ to_outside = target_function is not src_function
2528
+
2529
+ confirmed = called_function is None or called_function.returning is True
2530
+ self.kb.functions._add_fakeret_to(
2531
+ src_function.addr,
2532
+ src_node,
2533
+ dst_node,
2534
+ confirmed=confirmed,
2535
+ to_outside=to_outside,
2536
+ to_function_addr=called_function_addr,
2537
+ )
2538
+
2539
+ else:
2540
+ l.debug("Ignored jumpkind %s", jumpkind)
2541
+
2542
+ #
2543
+ # Other functions
2544
+ #
2545
+
2546
+ @staticmethod
2547
+ def _is_noop_block(arch: archinfo.Arch, block):
2548
+ """
2549
+ Check if the block is a no-op block by checking VEX statements.
2550
+
2551
+ :param arch: An architecture descriptor.
2552
+ :param block: The VEX block instance.
2553
+ :return: True if the entire block is a single-byte or multi-byte nop instruction, False otherwise.
2554
+ :rtype: bool
2555
+ """
2556
+
2557
+ if arch.name == "X86":
2558
+ if set(block.bytes) == {"b\x90"}:
2559
+ return True
2560
+ elif arch.name == "AMD64":
2561
+ if set(block.bytes) == {"b\x90"}:
2562
+ return True
2563
+ elif arch.name == "MIPS32":
2564
+ if arch.memory_endness == "Iend_BE":
2565
+ MIPS32_BE_NOOPS = {
2566
+ b"\x00\x20\x08\x25", # move $at, $at
2567
+ }
2568
+ insns = {block.bytes[i : i + 4] for i in range(0, block.size, 4)}
2569
+ if MIPS32_BE_NOOPS.issuperset(insns):
2570
+ return True
2571
+
2572
+ elif is_arm_arch(arch):
2573
+ if block.addr & 1 == 0:
2574
+ # ARM mode
2575
+ if arch.memory_endness == archinfo.Endness.LE:
2576
+ ARM_NOOPS = {
2577
+ b"\x00\x00\x00\x00", # andeq r0, r0, r0
2578
+ b"\x00\x00\xa0\xe1", # mov r0, r0
2579
+ }
2580
+ else: # if arch.memory_endness == archinfo.Endness.BE:
2581
+ ARM_NOOPS = {
2582
+ b"\x00\x00\x00\x00", # andeq r0, r0, r0
2583
+ b"\xe1\xa0\x00\x00", # mov r0, r0
2584
+ }
2585
+ insns = {block.bytes[i : i + 4] for i in range(0, block.size, 4)}
2586
+ if ARM_NOOPS.issuperset(insns):
2587
+ return True
2588
+
2589
+ else:
2590
+ # THUMB mode, 2-byte instructions
2591
+ if arch.memory_endness == archinfo.Endness.LE:
2592
+ THUMB_NOOPS = {
2593
+ b"\xc0\x46", # mov r8, r8
2594
+ b"\xb0\x00", # add sp, #0
2595
+ b"\x00\xbf", # nop
2596
+ }
2597
+ else:
2598
+ THUMB_NOOPS = {
2599
+ b"\x46\xc0", # mov r8, r8
2600
+ b"\x00\xb0", # add sp, #0
2601
+ b"\xbf\x00", # nop
2602
+ }
2603
+ insns = {block.bytes[i : i + 2] for i in range(0, block.size, 2)}
2604
+ if THUMB_NOOPS.issuperset(insns):
2605
+ return True
2606
+
2607
+ # Fallback
2608
+ # the block is a noop block if it only has IMark statements **and** it jumps to its immediate successor. VEX
2609
+ # will generate such blocks when opt_level==1 and cross_insn_opt is True
2610
+ fallthrough_addr = block.addr + block.size
2611
+ next_ = block.vex.next
2612
+ if isinstance(next_, pyvex.IRExpr.Const) and next_.con.value == fallthrough_addr:
2613
+ if all((type(stmt) is pyvex.IRStmt.IMark) for stmt in block.vex.statements):
2614
+ return True
2615
+
2616
+ # the block is a noop block if it only has IMark statements and IP-setting statements that set the IP to the
2617
+ # next location. VEX will generate such blocks when opt_level==1 and cross_insn_opt is False
2618
+ ip_offset = arch.ip_offset
2619
+ if all(
2620
+ (type(stmt) is pyvex.IRStmt.IMark or (type(stmt) is pyvex.IRStmt.Put and stmt.offset == ip_offset))
2621
+ for stmt in block.vex.statements
2622
+ ):
2623
+ if block.vex.statements:
2624
+ last_stmt = block.vex.statements[-1]
2625
+ if isinstance(last_stmt, pyvex.IRStmt.IMark):
2626
+ if isinstance(next_, pyvex.IRExpr.Const) and next_.con.value == fallthrough_addr:
2627
+ return True
2628
+ return False
2629
+
2630
+ @staticmethod
2631
+ def _is_noop_insn(insn):
2632
+ """
2633
+ Check if the instruction does nothing.
2634
+
2635
+ :param insn: The capstone insn object.
2636
+ :return: True if the instruction does no-op, False otherwise.
2637
+ """
2638
+
2639
+ insn_name = insn.insn_name()
2640
+
2641
+ if insn_name == "nop":
2642
+ # nops
2643
+ return True
2644
+ elif insn_name == "lea":
2645
+ # lea reg, [reg + 0]
2646
+ op0, op1 = insn.operands
2647
+ if op0.type == 1 and op1.type == 3:
2648
+ # reg and mem
2649
+ if op0.reg == op1.mem.base and op1.mem.index == 0 and op1.mem.disp == 0:
2650
+ return True
2651
+ elif insn_name == "mov":
2652
+ if len(insn.operands) > 2:
2653
+ # mov reg_a, imm1, shift imm2
2654
+ # This is not a NOP
2655
+ return False
2656
+ # mov reg_a, reg_a
2657
+ op0, op1 = insn.operands
2658
+ if op0.type == 1 and op1.type == 1:
2659
+ # reg and reg
2660
+ if op0.reg == op1.reg:
2661
+ return True
2662
+ elif insn_name in {"ud0", "ud1", "ud2"}:
2663
+ return True
2664
+
2665
+ # add more types of no-op instructions here :-)
2666
+
2667
+ return False
2668
+
2669
+ @classmethod
2670
+ def _get_nop_length(cls, insns):
2671
+ """
2672
+ Calculate the total size of leading nop instructions.
2673
+
2674
+ :param insns: A list of capstone insn objects.
2675
+ :return: Number of bytes of leading nop instructions.
2676
+ :rtype: int
2677
+ """
2678
+
2679
+ nop_length = 0
2680
+
2681
+ if insns and cls._is_noop_insn(insns[0]):
2682
+ # see where those nop instructions terminate
2683
+ for insn in insns:
2684
+ if cls._is_noop_insn(insn):
2685
+ nop_length += insn.size
2686
+ else:
2687
+ break
2688
+
2689
+ return nop_length
2690
+
2691
+ @staticmethod
2692
+ def _one_fakeret_node(all_edges):
2693
+ """
2694
+ Pick the first Ijk_FakeRet edge from all_edges, and return the destination node.
2695
+
2696
+ :param list all_edges: A list of networkx.Graph edges with data.
2697
+ :return: The first FakeRet node, or None if nothing is found.
2698
+ :rtype: CFGNode or None
2699
+ """
2700
+
2701
+ for _, dst, data in all_edges:
2702
+ if data.get("jumpkind", None) == "Ijk_FakeRet":
2703
+ return dst
2704
+ return None
2705
+
2706
+ def _lift(self, addr, *args, opt_level=1, cross_insn_opt=False, **kwargs):
2707
+ """
2708
+ Lift a basic block of code. Will use the base state as a source of bytes if possible.
2709
+ """
2710
+ if "backup_state" not in kwargs:
2711
+ kwargs["backup_state"] = self._base_state
2712
+ return self.project.factory.block(addr, *args, opt_level=opt_level, cross_insn_opt=cross_insn_opt, **kwargs)
2713
+
2714
+ #
2715
+ # Indirect jumps processing
2716
+ #
2717
+
2718
+ def _resolve_indirect_jump_timelessly(self, addr, block, func_addr, jumpkind):
2719
+ """
2720
+ Attempt to quickly resolve an indirect jump.
2721
+
2722
+ :param int addr: Basic block address of this indirect jump.
2723
+ :param block: The basic block. The type is determined by the backend being used. It's pyvex.IRSB if
2724
+ pyvex is used as the backend.
2725
+ :param int func_addr: Address of the function that this indirect jump belongs to.
2726
+ :param str jumpkind: The jumpkind.
2727
+ :return: A tuple of a boolean indicating whether the resolution is successful or not, and a list
2728
+ of resolved targets (ints).
2729
+ :rtype: tuple
2730
+ """
2731
+
2732
+ # pre-check: if re-lifting the block with full optimization (cross-instruction-optimization enabled) gives us
2733
+ # a constant next expression, we don't need to resolve it
2734
+ try:
2735
+ relifted = self.project.factory.block(block.addr, size=block.size, opt_level=1, cross_insn_opt=True).vex
2736
+ except SimError:
2737
+ return False, []
2738
+ if isinstance(relifted.next, pyvex.IRExpr.Const):
2739
+ # yes!
2740
+ return True, [relifted.next.con.value]
2741
+
2742
+ if block.statements is None:
2743
+ # make sure there are statements
2744
+ block = self.project.factory.block(block.addr, size=block.size).vex
2745
+
2746
+ for res in self.timeless_indirect_jump_resolvers:
2747
+ if res.filter(self, addr, func_addr, block, jumpkind):
2748
+ r, resolved_targets = res.resolve(self, addr, func_addr, block, jumpkind)
2749
+ if r:
2750
+ return True, resolved_targets
2751
+ return False, []
2752
+
2753
+ def _indirect_jump_resolved(self, jump, jump_addr, resolved_by, targets):
2754
+ """
2755
+ Called when an indirect jump is successfully resolved.
2756
+
2757
+ :param IndirectJump jump: The resolved indirect jump, or None if an IndirectJump instance is
2758
+ not available.
2759
+ :param int jump_addr: Address of the resolved indirect jump.
2760
+ :param IndirectJumpResolver resolved_by: The resolver used to resolve this indirect jump.
2761
+ :param list targets: List of indirect jump targets.
2762
+ :param CFGJob job: The job at the start of the block containing the indirect jump.
2763
+
2764
+ :return: None
2765
+ """
2766
+
2767
+ addr = jump.addr if jump is not None else jump_addr
2768
+ l.debug(
2769
+ "The indirect jump at %#x is successfully resolved by %s. It has %d targets.",
2770
+ addr,
2771
+ resolved_by,
2772
+ len(targets),
2773
+ )
2774
+ self.kb.indirect_jumps.update_resolved_addrs(addr, targets)
2775
+
2776
+ def _indirect_jump_unresolved(self, jump):
2777
+ """
2778
+ Called when we cannot resolve an indirect jump.
2779
+
2780
+ :param IndirectJump jump: The unresolved indirect jump.
2781
+
2782
+ :return: None
2783
+ """
2784
+
2785
+ l.debug("Failed to resolve the indirect jump at %#x.", jump.addr)
2786
+ # tell KnowledgeBase that it's not resolved
2787
+ # TODO: self.kb._unresolved_indirect_jumps is not processed during normalization. Fix it.
2788
+ self.kb.unresolved_indirect_jumps.add(jump.addr)
2789
+
2790
+ def _indirect_jump_encountered(
2791
+ self,
2792
+ addr: int,
2793
+ cfg_node: CFGNode,
2794
+ irsb: pyvex.IRSB,
2795
+ func_addr: int,
2796
+ stmt_idx: int | str = DEFAULT_STATEMENT,
2797
+ ) -> tuple[bool, set[int], IndirectJump | None]:
2798
+ """
2799
+ Called when we encounter an indirect jump. We will try to resolve this indirect jump using timeless (fast)
2800
+ indirect jump resolvers. If it cannot be resolved, we will see if this indirect jump has been resolved before.
2801
+
2802
+ :param addr: Address of the block containing the indirect jump.
2803
+ :param cfg_node: The CFGNode instance of the block that contains the indirect jump.
2804
+ :param irsb: The IRSB instance of the block that contains the indirect jump. It must be lifted with
2805
+ cross-instruction optimization disabled (cross_insn_opt=True when opt_level=1, or
2806
+ opt_level=0).
2807
+ :param func_addr: Address of the current function.
2808
+ :param stmt_idx: ID of the source statement.
2809
+
2810
+ :return: A 3-tuple of (whether it is resolved or not, all resolved targets, an IndirectJump object
2811
+ if there is one or None otherwise)
2812
+ """
2813
+
2814
+ jumpkind = irsb.jumpkind
2815
+ l.debug("IRSB %#x has an indirect jump (%s) as its default exit.", addr, jumpkind)
2816
+
2817
+ # try resolving it fast
2818
+ resolved, resolved_targets = self._resolve_indirect_jump_timelessly(addr, irsb, func_addr, jumpkind)
2819
+ if resolved:
2820
+ l.debug(
2821
+ "Indirect jump at block %#x is resolved by a timeless indirect jump resolver. %d targets found.",
2822
+ addr,
2823
+ len(resolved_targets),
2824
+ )
2825
+ return True, set(resolved_targets), None
2826
+
2827
+ l.debug("Indirect jump at block %#x cannot be resolved by a timeless indirect jump resolver.", addr)
2828
+
2829
+ # Add it to our set. Will process it later if user allows.
2830
+ # Create an IndirectJump instance
2831
+ if addr not in self.indirect_jumps:
2832
+ if self.project.arch.branch_delay_slot:
2833
+ if len(cfg_node.instruction_addrs) < 2:
2834
+ # sanity check
2835
+ # decoding failed when decoding the second instruction (or even the first instruction)
2836
+ return False, set(), None
2837
+ ins_addr = cfg_node.instruction_addrs[-2]
2838
+ elif cfg_node.instruction_addrs:
2839
+ ins_addr = cfg_node.instruction_addrs[-1]
2840
+ else:
2841
+ # fallback
2842
+ ins_addr = addr
2843
+ assert jumpkind is not None
2844
+ ij = IndirectJump(addr, ins_addr, func_addr, jumpkind, stmt_idx, resolved_targets=[])
2845
+ self.indirect_jumps[addr] = ij
2846
+ resolved = False
2847
+ else:
2848
+ ij: IndirectJump = self.indirect_jumps[addr]
2849
+ resolved = len(ij.resolved_targets) > 0
2850
+
2851
+ return resolved, ij.resolved_targets, ij
2852
+
2853
+ def _process_unresolved_indirect_jumps(self):
2854
+ """
2855
+ Resolve all unresolved indirect jumps found in previous scanning.
2856
+
2857
+ Currently we support resolving the following types of indirect jumps:
2858
+ - Ijk_Call: indirect calls where the function address is passed in from a proceeding basic block
2859
+ - Ijk_Boring: jump tables
2860
+ - For an up-to-date list, see analyses/cfg/indirect_jump_resolvers
2861
+
2862
+ :return: A set of concrete indirect jump targets (ints).
2863
+ :rtype: set
2864
+ """
2865
+
2866
+ l.info("%d indirect jumps to resolve.", len(self._indirect_jumps_to_resolve))
2867
+
2868
+ all_targets = set()
2869
+ idx: int
2870
+ jump: IndirectJump
2871
+ for idx, jump in enumerate(self._indirect_jumps_to_resolve):
2872
+ if self._low_priority:
2873
+ self._release_gil(idx, 50, 0.000001)
2874
+ all_targets |= self._process_one_indirect_jump(jump)
2875
+
2876
+ self._indirect_jumps_to_resolve.clear()
2877
+
2878
+ return all_targets
2879
+
2880
+ def _process_one_indirect_jump(self, jump: IndirectJump, func_graph_complete: bool = True) -> set:
2881
+ """
2882
+ Resolve a given indirect jump.
2883
+
2884
+ :param jump: The IndirectJump instance.
2885
+ :param func_graph_complete: True if the function graph is complete at this point (except for this indirect jump
2886
+ and all nodes that it dominates). Indirect jump resolvers may use the current
2887
+ function graph to perform sanity checks. CFGEmulated sets func_graph_complete to
2888
+ False while CFGFast sets it to True (because in CFGFast, indirect jumps are always
2889
+ resolved after direct jump jobs are processed).
2890
+ :return: A set of resolved indirect jump targets (ints).
2891
+ """
2892
+
2893
+ resolved = False
2894
+ resolved_by = None
2895
+ targets = None
2896
+
2897
+ block = self._lift(jump.addr)
2898
+
2899
+ for resolver in self.indirect_jump_resolvers:
2900
+ resolver.base_state = self._base_state
2901
+
2902
+ if not resolver.filter(self, jump.addr, jump.func_addr, block, jump.jumpkind):
2903
+ continue
2904
+
2905
+ resolved, targets = resolver.resolve(
2906
+ self, jump.addr, jump.func_addr, block, jump.jumpkind, func_graph_complete=func_graph_complete
2907
+ )
2908
+ if resolved:
2909
+ resolved_by = resolver
2910
+ break
2911
+
2912
+ if resolved:
2913
+ self._indirect_jump_resolved(jump, jump.addr, resolved_by, targets)
2914
+ else:
2915
+ self._indirect_jump_unresolved(jump)
2916
+
2917
+ return set() if targets is None else set(targets)