angr 9.2.138__py3-none-win_amd64.whl → 9.2.140__py3-none-win_amd64.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 (101) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/calling_convention/calling_convention.py +48 -21
  3. angr/analyses/calling_convention/fact_collector.py +59 -12
  4. angr/analyses/calling_convention/utils.py +2 -2
  5. angr/analyses/cfg/cfg_base.py +13 -0
  6. angr/analyses/cfg/cfg_fast.py +23 -4
  7. angr/analyses/decompiler/ail_simplifier.py +79 -53
  8. angr/analyses/decompiler/block_simplifier.py +0 -2
  9. angr/analyses/decompiler/callsite_maker.py +80 -14
  10. angr/analyses/decompiler/clinic.py +99 -80
  11. angr/analyses/decompiler/condition_processor.py +2 -2
  12. angr/analyses/decompiler/decompiler.py +19 -7
  13. angr/analyses/decompiler/dephication/rewriting_engine.py +16 -7
  14. angr/analyses/decompiler/expression_narrower.py +1 -1
  15. angr/analyses/decompiler/optimization_passes/__init__.py +3 -0
  16. angr/analyses/decompiler/optimization_passes/condition_constprop.py +149 -0
  17. angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +8 -7
  18. angr/analyses/decompiler/optimization_passes/deadblock_remover.py +12 -3
  19. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +1 -1
  20. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +21 -13
  21. angr/analyses/decompiler/optimization_passes/optimization_pass.py +21 -12
  22. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +17 -9
  23. angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +7 -10
  24. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +12 -1
  25. angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +61 -25
  26. angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +50 -1
  27. angr/analyses/decompiler/presets/fast.py +2 -0
  28. angr/analyses/decompiler/presets/full.py +2 -0
  29. angr/analyses/decompiler/region_simplifiers/expr_folding.py +259 -108
  30. angr/analyses/decompiler/region_simplifiers/region_simplifier.py +28 -9
  31. angr/analyses/decompiler/ssailification/rewriting_engine.py +20 -2
  32. angr/analyses/decompiler/ssailification/traversal_engine.py +4 -3
  33. angr/analyses/decompiler/structured_codegen/c.py +10 -3
  34. angr/analyses/decompiler/structuring/dream.py +28 -19
  35. angr/analyses/decompiler/structuring/phoenix.py +253 -89
  36. angr/analyses/decompiler/structuring/recursive_structurer.py +1 -0
  37. angr/analyses/decompiler/structuring/structurer_base.py +121 -46
  38. angr/analyses/decompiler/structuring/structurer_nodes.py +6 -1
  39. angr/analyses/decompiler/utils.py +60 -1
  40. angr/analyses/deobfuscator/api_obf_finder.py +13 -5
  41. angr/analyses/deobfuscator/api_obf_type2_finder.py +166 -0
  42. angr/analyses/deobfuscator/string_obf_finder.py +105 -18
  43. angr/analyses/forward_analysis/forward_analysis.py +1 -1
  44. angr/analyses/propagator/top_checker_mixin.py +6 -6
  45. angr/analyses/reaching_definitions/__init__.py +2 -1
  46. angr/analyses/reaching_definitions/dep_graph.py +1 -12
  47. angr/analyses/reaching_definitions/engine_vex.py +36 -31
  48. angr/analyses/reaching_definitions/function_handler.py +15 -2
  49. angr/analyses/reaching_definitions/rd_state.py +1 -37
  50. angr/analyses/reaching_definitions/reaching_definitions.py +13 -24
  51. angr/analyses/s_propagator.py +129 -87
  52. angr/analyses/s_reaching_definitions/s_rda_model.py +7 -1
  53. angr/analyses/s_reaching_definitions/s_rda_view.py +2 -2
  54. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +3 -1
  55. angr/analyses/stack_pointer_tracker.py +36 -22
  56. angr/analyses/typehoon/simple_solver.py +45 -7
  57. angr/analyses/typehoon/typeconsts.py +18 -5
  58. angr/analyses/variable_recovery/engine_ail.py +1 -1
  59. angr/analyses/variable_recovery/engine_base.py +62 -67
  60. angr/analyses/variable_recovery/engine_vex.py +1 -1
  61. angr/analyses/variable_recovery/irsb_scanner.py +2 -2
  62. angr/block.py +69 -107
  63. angr/callable.py +14 -7
  64. angr/calling_conventions.py +81 -10
  65. angr/distributed/__init__.py +1 -1
  66. angr/engines/__init__.py +7 -8
  67. angr/engines/engine.py +3 -138
  68. angr/engines/failure.py +2 -2
  69. angr/engines/hook.py +2 -2
  70. angr/engines/light/engine.py +5 -10
  71. angr/engines/pcode/emulate.py +2 -2
  72. angr/engines/pcode/engine.py +2 -14
  73. angr/engines/pcode/lifter.py +2 -2
  74. angr/engines/procedure.py +2 -2
  75. angr/engines/soot/engine.py +2 -2
  76. angr/engines/soot/statements/switch.py +1 -1
  77. angr/engines/successors.py +123 -17
  78. angr/engines/syscall.py +2 -2
  79. angr/engines/unicorn.py +3 -3
  80. angr/engines/vex/heavy/heavy.py +3 -15
  81. angr/engines/vex/lifter.py +2 -2
  82. angr/engines/vex/light/light.py +2 -2
  83. angr/factory.py +4 -19
  84. angr/knowledge_plugins/cfg/cfg_model.py +3 -2
  85. angr/knowledge_plugins/key_definitions/atoms.py +8 -4
  86. angr/knowledge_plugins/key_definitions/live_definitions.py +41 -103
  87. angr/knowledge_plugins/labels.py +2 -2
  88. angr/knowledge_plugins/obfuscations.py +1 -0
  89. angr/knowledge_plugins/xrefs/xref_manager.py +4 -0
  90. angr/lib/angr_native.dll +0 -0
  91. angr/sim_type.py +19 -17
  92. angr/state_plugins/plugin.py +19 -4
  93. angr/storage/memory_mixins/memory_mixin.py +1 -1
  94. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +10 -5
  95. angr/utils/ssa/__init__.py +119 -4
  96. {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/METADATA +6 -6
  97. {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/RECORD +101 -99
  98. {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/LICENSE +0 -0
  99. {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/WHEEL +0 -0
  100. {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/entry_points.txt +0 -0
  101. {angr-9.2.138.dist-info → angr-9.2.140.dist-info}/top_level.txt +0 -0
angr/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
  # pylint: disable=wrong-import-position
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "9.2.138"
5
+ __version__ = "9.2.140"
6
6
 
7
7
  if bytes is str:
8
8
  raise Exception(
@@ -150,6 +150,8 @@ class CallingConventionAnalysis(Analysis):
150
150
  The major analysis routine.
151
151
  """
152
152
 
153
+ assert self._function is not None
154
+
153
155
  if self._function.is_simprocedure:
154
156
  hooker = self.project.hooked_by(self._function.addr)
155
157
  if isinstance(
@@ -200,8 +202,8 @@ class CallingConventionAnalysis(Analysis):
200
202
  )
201
203
  if prototype.args:
202
204
  break
203
- self.cc = cc
204
- self.prototype = prototype
205
+ self.cc = cc # type: ignore
206
+ self.prototype = prototype # type: ignore
205
207
  return
206
208
  if self._function.is_plt:
207
209
  r = self._analyze_plt()
@@ -218,23 +220,33 @@ class CallingConventionAnalysis(Analysis):
218
220
  if self.analyze_callsites:
219
221
  # only take the first 3 because running reaching definition analysis on all functions is costly
220
222
  callsite_facts = self._extract_and_analyze_callsites(max_analyzing_callsites=3)
221
- prototype = self._adjust_prototype(
222
- prototype, callsite_facts, update_arguments=UpdateArgumentsOption.UpdateWhenCCHasNoArgs
223
+ prototype = (
224
+ self._adjust_prototype(
225
+ prototype, callsite_facts, update_arguments=UpdateArgumentsOption.UpdateWhenCCHasNoArgs
226
+ )
227
+ if prototype is not None
228
+ else None
223
229
  )
224
230
 
225
231
  self.cc = cc
226
232
  self.prototype = prototype
227
233
 
228
234
  def _analyze_callsite_only(self):
235
+ assert self.caller_func_addr is not None
236
+ assert self.callsite_block_addr is not None
237
+ assert self.callsite_insn_addr is not None
238
+ cc, prototype = None, None
239
+
229
240
  for include_callsite_preds in [False, True]:
230
- callsite_facts = [
231
- self._analyze_callsite(
232
- self.caller_func_addr,
233
- self.callsite_block_addr,
234
- self.callsite_insn_addr,
235
- include_preds=include_callsite_preds,
236
- )
237
- ]
241
+ fact = self._analyze_callsite(
242
+ self.caller_func_addr,
243
+ self.callsite_block_addr,
244
+ self.callsite_insn_addr,
245
+ include_preds=include_callsite_preds,
246
+ )
247
+ if fact is None:
248
+ continue
249
+ callsite_facts = [fact]
238
250
  cc_cls = default_cc(
239
251
  self.project.arch.name,
240
252
  platform=(
@@ -258,6 +270,7 @@ class CallingConventionAnalysis(Analysis):
258
270
 
259
271
  :return: A calling convention.
260
272
  """
273
+ assert self._function is not None
261
274
 
262
275
  if len(self._function.jumpout_sites) != 1:
263
276
  l.warning(
@@ -314,6 +327,7 @@ class CallingConventionAnalysis(Analysis):
314
327
  Go over the variable information in variable manager for this function, and return all uninitialized
315
328
  register/stack variables.
316
329
  """
330
+ assert self._function is not None
317
331
 
318
332
  if self._function.is_simprocedure or self._function.is_plt:
319
333
  # we do not analyze SimProcedures or PLT stubs
@@ -403,6 +417,8 @@ class CallingConventionAnalysis(Analysis):
403
417
  returns anything or not.
404
418
  """
405
419
 
420
+ assert self._function is not None
421
+
406
422
  if self._cfg is None:
407
423
  l.warning("CFG is not provided. Skip calling convention analysis at call sites.")
408
424
  return []
@@ -656,13 +672,10 @@ class CallingConventionAnalysis(Analysis):
656
672
 
657
673
  def _adjust_prototype(
658
674
  self,
659
- proto: SimTypeFunction | None,
675
+ proto: SimTypeFunction,
660
676
  facts: list[CallSiteFact],
661
677
  update_arguments: int = UpdateArgumentsOption.DoNotUpdate,
662
- ) -> SimTypeFunction | None:
663
- if proto is None:
664
- return None
665
-
678
+ ) -> SimTypeFunction:
666
679
  # is the return value used anywhere?
667
680
  if facts:
668
681
  if all(fact.return_value_used is False for fact in facts):
@@ -691,6 +704,8 @@ class CallingConventionAnalysis(Analysis):
691
704
  :return:
692
705
  """
693
706
 
707
+ assert self._function is not None
708
+
694
709
  args = set()
695
710
  ret_addr_offset = 0 if not self.project.arch.call_pushes_ret else self.project.arch.bytes
696
711
 
@@ -839,17 +854,27 @@ class CallingConventionAnalysis(Analysis):
839
854
  return SimTypeBottom()
840
855
 
841
856
  def _guess_retval_type(self, cc: SimCC, ret_val_size: int | None) -> SimType:
857
+ assert self._function is not None
858
+
842
859
  if cc.FP_RETURN_VAL and self._function.ret_sites:
843
860
  # examine the last block of the function and see which registers are assigned to
844
861
  for ret_block in self._function.ret_sites:
862
+ fpretval_updated, retval_updated = False, False
863
+ fp_reg_size = 0
845
864
  irsb = self.project.factory.block(ret_block.addr, size=ret_block.size).vex
846
865
  for stmt in irsb.statements:
847
866
  if isinstance(stmt, Put) and isinstance(stmt.data, RdTmp):
848
- reg_size = irsb.tyenv.sizeof(stmt.data.tmp) // self.project.arch.byte_width
867
+ reg_size = irsb.tyenv.sizeof(stmt.data.tmp) // self.project.arch.byte_width # type: ignore
849
868
  reg_name = self.project.arch.translate_register_name(stmt.offset, size=reg_size)
850
- if reg_name == cc.FP_RETURN_VAL.reg_name:
851
- # possibly float
852
- return SimTypeFloat() if reg_size == 4 else SimTypeDouble()
869
+ if isinstance(cc.FP_RETURN_VAL, SimRegArg) and reg_name == cc.FP_RETURN_VAL.reg_name:
870
+ fpretval_updated = True
871
+ fp_reg_size = reg_size
872
+ elif isinstance(cc.RETURN_VAL, SimRegArg) and reg_name == cc.RETURN_VAL.reg_name:
873
+ retval_updated = True
874
+
875
+ if fpretval_updated and not retval_updated:
876
+ # possibly float
877
+ return SimTypeFloat() if fp_reg_size == 4 else SimTypeDouble()
853
878
 
854
879
  if ret_val_size is not None:
855
880
  if ret_val_size == 1:
@@ -884,6 +909,8 @@ class CallingConventionAnalysis(Analysis):
884
909
  # TODO: Use a better pattern matching approach
885
910
  if len(func.block_addrs_set) < 3:
886
911
  return False, None
912
+ if func.startpoint is None:
913
+ return False, None
887
914
 
888
915
  head = func.startpoint
889
916
  out_edges = list(func.transition_graph.out_edges(head, data=True))
@@ -1,3 +1,4 @@
1
+ # pylint:disable=too-many-boolean-expressions
1
2
  from __future__ import annotations
2
3
  from typing import Any
3
4
 
@@ -332,6 +333,9 @@ class FactCollector(Analysis):
332
333
  cc_cls = default_cc(
333
334
  self.project.arch.name, platform=self.project.simos.name if self.project.simos is not None else None
334
335
  )
336
+ if cc_cls is None:
337
+ # don't know what the calling convention may be... give up
338
+ return
335
339
  cc = cc_cls(self.project.arch)
336
340
  if isinstance(cc.RETURN_VAL, SimRegArg):
337
341
  retreg_offset = cc.RETURN_VAL.check_offset(self.project.arch)
@@ -401,6 +405,16 @@ class FactCollector(Analysis):
401
405
  func_graph = self.function.transition_graph
402
406
  callee_restored_regs = set()
403
407
 
408
+ sp_masks = {
409
+ 0xFFFFFFFE,
410
+ 0xFFFFFFFC,
411
+ 0xFFFFFFF8,
412
+ 0xFFFFFFF0,
413
+ 0xFFFFFFFF_FFFFFFFE,
414
+ 0xFFFFFFFF_FFFFFFFC,
415
+ 0xFFFFFFFF_FFFFFFF8,
416
+ 0xFFFFFFFF_FFFFFFF0,
417
+ }
404
418
  for endpoint in self.function.endpoints:
405
419
  traversed = set()
406
420
  queue: list[tuple[int, BlockNode | HookNode]] = [(0, endpoint)]
@@ -434,17 +448,29 @@ class FactCollector(Analysis):
434
448
  tmps[stmt.tmp] = "stack_value"
435
449
  elif isinstance(stmt.data, pyvex.IRExpr.Const):
436
450
  tmps[stmt.tmp] = "const"
437
- elif isinstance(stmt.data, pyvex.IRExpr.Binop) and ( # noqa:SIM102
438
- stmt.data.op.startswith("Iop_Add") or stmt.data.op.startswith("Iop_Sub")
439
- ):
440
- if (
441
- isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp)
442
- and tmps.get(stmt.data.args[0].tmp) == "sp"
443
- ) or (
444
- isinstance(stmt.data.args[1], pyvex.IRExpr.RdTmp)
445
- and tmps.get(stmt.data.args[1].tmp) == "sp"
446
- ):
447
- tmps[stmt.tmp] = "sp"
451
+ elif isinstance(stmt.data, pyvex.IRExpr.Binop):
452
+ if stmt.data.op.startswith("Iop_Add") or stmt.data.op.startswith("Iop_Sub"):
453
+ if (
454
+ isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp)
455
+ and tmps.get(stmt.data.args[0].tmp) == "sp"
456
+ ) or (
457
+ isinstance(stmt.data.args[1], pyvex.IRExpr.RdTmp)
458
+ and tmps.get(stmt.data.args[1].tmp) == "sp"
459
+ ):
460
+ tmps[stmt.tmp] = "sp"
461
+ elif stmt.data.op.startswith("Iop_And"): # noqa: SIM102
462
+ if (
463
+ isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp)
464
+ and tmps.get(stmt.data.args[0].tmp) == "sp"
465
+ and isinstance(stmt.data.args[1], pyvex.IRExpr.Const)
466
+ and stmt.data.args[1].con.value in sp_masks
467
+ ) or (
468
+ isinstance(stmt.data.args[1], pyvex.IRExpr.RdTmp)
469
+ and tmps.get(stmt.data.args[1].tmp) == "sp"
470
+ and isinstance(stmt.data.args[0], pyvex.IRExpr.Const)
471
+ and stmt.data.args[0].con.value in sp_masks
472
+ ):
473
+ tmps[stmt.tmp] = "sp"
448
474
  if isinstance(stmt, pyvex.IRStmt.Put):
449
475
  size = stmt.data.result_size(block.vex.tyenv) // self.project.arch.byte_width
450
476
  # is the data loaded from the stack?
@@ -460,7 +486,28 @@ class FactCollector(Analysis):
460
486
  if pred not in traversed and depth + 1 <= self._max_depth and edge_type == "transition":
461
487
  queue.append((depth + 1, pred))
462
488
 
463
- return callee_restored_regs
489
+ # remove offsets of registers that may store return values from callee_restored_regs
490
+ ret_reg_offsets = set()
491
+ cc_cls = default_cc(
492
+ self.project.arch.name, platform=self.project.simos.name if self.project.simos is not None else None
493
+ )
494
+ if cc_cls is not None:
495
+ cc = cc_cls(self.project.arch)
496
+ if isinstance(cc.RETURN_VAL, SimRegArg):
497
+ retreg_offset = cc.RETURN_VAL.check_offset(self.project.arch)
498
+ ret_reg_offsets.add(retreg_offset)
499
+ if isinstance(cc.OVERFLOW_RETURN_VAL, SimRegArg):
500
+ retreg_offset = cc.OVERFLOW_RETURN_VAL.check_offset(self.project.arch)
501
+ ret_reg_offsets.add(retreg_offset)
502
+ if isinstance(cc.FP_RETURN_VAL, SimRegArg):
503
+ try:
504
+ retreg_offset = cc.FP_RETURN_VAL.check_offset(self.project.arch)
505
+ ret_reg_offsets.add(retreg_offset)
506
+ except KeyError:
507
+ # register name does not exist
508
+ pass
509
+
510
+ return callee_restored_regs.difference(ret_reg_offsets)
464
511
 
465
512
  def _determine_input_args(self, end_states: list[FactCollectorState], callee_restored_regs: set[int]) -> None:
466
513
  self.input_args = []
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
  import logging
3
3
 
4
4
  import archinfo
5
- from archinfo.arch_arm import is_arm_arch, ArchARMHF
5
+ from archinfo.arch_arm import is_arm_arch, ArchARMHF, ArchARMCortexM
6
6
 
7
7
  from angr.calling_conventions import SimCC
8
8
 
@@ -37,7 +37,7 @@ def is_sane_register_variable(arch: archinfo.Arch, reg_offset: int, reg_size: in
37
37
  # 224 <= reg_offset < 480) # xmm0-xmm7
38
38
 
39
39
  if is_arm_arch(arch):
40
- if isinstance(arch, ArchARMHF):
40
+ if isinstance(arch, (ArchARMHF, ArchARMCortexM)):
41
41
  return 8 <= reg_offset < 24 or 128 <= reg_offset < 160 # r0 - 32 # s0 - s7, or d0 - d4
42
42
  return 8 <= reg_offset < 24 # r0-r3
43
43
 
@@ -1421,6 +1421,19 @@ class CFGBase(Analysis):
1421
1421
  # We gotta create a new one
1422
1422
  l.error("normalize(): Please report it to Fish.")
1423
1423
 
1424
+ # update the jump tables dict and the indirect jumps dict
1425
+ if smallest_node.addr not in self.model.jump_tables:
1426
+ for n in other_nodes:
1427
+ if n.addr in self.model.jump_tables:
1428
+ self.model.jump_tables[n.addr].addr = smallest_node.addr
1429
+ self.model.jump_tables[smallest_node.addr] = self.model.jump_tables[n.addr]
1430
+ break
1431
+ if smallest_node.addr not in self.indirect_jumps:
1432
+ for n in other_nodes:
1433
+ if n.addr in self.indirect_jumps:
1434
+ self.indirect_jumps[n.addr].addr = smallest_node.addr
1435
+ self.indirect_jumps[smallest_node.addr] = self.indirect_jumps[n.addr]
1436
+ break
1424
1437
  # deal with duplicated entries in self.jump_tables and self.indirect_jumps
1425
1438
  if smallest_node.addr in self.model.jump_tables:
1426
1439
  for n in other_nodes:
@@ -1524,6 +1524,17 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
1524
1524
  }:
1525
1525
  func.info["is_rust_probestack"] = True
1526
1526
 
1527
+ # determine if the function is __alloca_probe
1528
+ if func is not None and len(func.block_addrs_set) == 4:
1529
+ block_bytes = {func.get_block(block_addr).bytes for block_addr in func.block_addrs_set}
1530
+ if block_bytes == {
1531
+ b"H\x83\xec\x10L\x89\x14$L\x89\\$\x08M3\xdbL\x8dT$\x18L+\xd0M\x0fB\xd3eL\x8b\x1c%\x10\x00\x00\x00M;\xd3s\x16",
1532
+ b"fA\x81\xe2\x00\xf0M\x8d\x9b\x00\xf0\xff\xffA\xc6\x03\x00M;\xd3u\xf0",
1533
+ b"M\x8d\x9b\x00\xf0\xff\xffA\xc6\x03\x00M;\xd3u\xf0",
1534
+ b"L\x8b\x14$L\x8b\\$\x08H\x83\xc4\x10\xc3",
1535
+ }:
1536
+ func.info["is_alloca_probe"] = True
1537
+
1527
1538
  if self._collect_data_ref and self.project is not None and ":" in self.project.arch.name:
1528
1539
  # this is a pcode arch - use Clinic to recover data references
1529
1540
 
@@ -2819,11 +2830,13 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
2819
2830
  if sec is not None and sec.is_readable and not sec.is_writable:
2820
2831
  # points to a non-writable region. read it out and see if there is another pointer!
2821
2832
  v = self._fast_memory_load_pointer(ref.data_addr, ref.data_size)
2833
+ if v is None:
2834
+ return
2822
2835
 
2823
2836
  # this value can either be a pointer or an offset from the pc... we need to try them both
2824
2837
  # attempt 1: a direct pointer
2825
2838
  sec_2nd = self.project.loader.find_section_containing(v)
2826
- if sec_2nd is not None and sec_2nd.is_readable and not sec_2nd.is_writable:
2839
+ if sec_2nd is not None and sec_2nd.is_readable:
2827
2840
  # found it!
2828
2841
  self._add_data_reference(
2829
2842
  irsb_addr,
@@ -2872,7 +2885,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
2872
2885
  actual_ref_ins_addr = ref.ins_addr + 4
2873
2886
  v += 8 + actual_ref_ins_addr
2874
2887
  sec_3rd = self.project.loader.find_section_containing(v)
2875
- if sec_3rd is not None and sec_3rd.is_readable and not sec_3rd.is_writable:
2888
+ if sec_3rd is not None and sec_3rd.is_readable:
2876
2889
  # found it!
2877
2890
  self._add_data_reference(
2878
2891
  irsb_addr, ref.stmt_idx, actual_ref_ins_addr, v, data_size=None, data_type=MemoryDataSort.Unknown
@@ -4178,7 +4191,10 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
4178
4191
  for segment in self.project.loader.main_object.segments:
4179
4192
  if segment.is_readable and segment.memsize >= 8:
4180
4193
  # the gp area is sometimes writable, so we can't test for (not segment.is_writable)
4181
- content = self.project.loader.memory.load(segment.vaddr, segment.memsize)
4194
+ try:
4195
+ content = self.project.loader.memory.load(segment.vaddr, segment.memsize)
4196
+ except KeyError:
4197
+ continue
4182
4198
  content_buf = pyvex.ffi.from_buffer(content)
4183
4199
  self._ro_region_cdata_cache.append(content_buf)
4184
4200
  pyvex.pvc.register_readonly_region(segment.vaddr, segment.memsize, content_buf)
@@ -4187,7 +4203,10 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
4187
4203
  # also map .got
4188
4204
  for section in self.project.loader.main_object.sections:
4189
4205
  if section.name == ".got":
4190
- content = self.project.loader.memory.load(section.vaddr, section.memsize)
4206
+ try:
4207
+ content = self.project.loader.memory.load(section.vaddr, section.memsize)
4208
+ except KeyError:
4209
+ continue
4191
4210
  content_buf = pyvex.ffi.from_buffer(content)
4192
4211
  self._ro_region_cdata_cache.append(content_buf)
4193
4212
  pyvex.pvc.register_readonly_region(section.vaddr, section.memsize, content_buf)