angr 9.2.159__cp310-abi3-macosx_11_0_arm64.whl → 9.2.161__cp310-abi3-macosx_11_0_arm64.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 (37) hide show
  1. angr/__init__.py +4 -1
  2. angr/analyses/decompiler/ail_simplifier.py +81 -1
  3. angr/analyses/decompiler/block_simplifier.py +7 -5
  4. angr/analyses/decompiler/clinic.py +5 -1
  5. angr/analyses/decompiler/decompiler.py +12 -9
  6. angr/analyses/decompiler/peephole_optimizations/__init__.py +4 -4
  7. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +53 -0
  8. angr/analyses/decompiler/peephole_optimizations/modulo_simplifier.py +89 -0
  9. angr/analyses/decompiler/peephole_optimizations/{const_mull_a_shift.py → optimized_div_simplifier.py} +139 -25
  10. angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +18 -9
  11. angr/analyses/decompiler/structuring/phoenix.py +19 -32
  12. angr/analyses/s_reaching_definitions/s_rda_model.py +1 -0
  13. angr/analyses/s_reaching_definitions/s_reaching_definitions.py +5 -2
  14. angr/analyses/typehoon/simple_solver.py +231 -29
  15. angr/analyses/typehoon/typehoon.py +10 -2
  16. angr/analyses/variable_recovery/engine_ail.py +8 -20
  17. angr/analyses/variable_recovery/engine_base.py +9 -1
  18. angr/analyses/variable_recovery/variable_recovery_base.py +30 -2
  19. angr/analyses/variable_recovery/variable_recovery_fast.py +11 -2
  20. angr/emulator.py +143 -0
  21. angr/engines/concrete.py +66 -0
  22. angr/engines/icicle.py +66 -30
  23. angr/exploration_techniques/driller_core.py +2 -2
  24. angr/project.py +7 -0
  25. angr/rustylib.abi3.so +0 -0
  26. angr/sim_type.py +16 -8
  27. angr/state_plugins/unicorn_engine.py +4 -4
  28. angr/{lib/angr_native.dylib → unicornlib.dylib} +0 -0
  29. angr/utils/graph.py +20 -1
  30. angr/utils/ssa/__init__.py +3 -3
  31. {angr-9.2.159.dist-info → angr-9.2.161.dist-info}/METADATA +5 -6
  32. {angr-9.2.159.dist-info → angr-9.2.161.dist-info}/RECORD +36 -34
  33. angr/analyses/decompiler/peephole_optimizations/a_sub_a_div_const_mul_const.py +0 -57
  34. {angr-9.2.159.dist-info → angr-9.2.161.dist-info}/WHEEL +0 -0
  35. {angr-9.2.159.dist-info → angr-9.2.161.dist-info}/entry_points.txt +0 -0
  36. {angr-9.2.159.dist-info → angr-9.2.161.dist-info}/licenses/LICENSE +0 -0
  37. {angr-9.2.159.dist-info → angr-9.2.161.dist-info}/top_level.txt +0 -0
@@ -525,6 +525,10 @@ class SimEngineVRBase(
525
525
  def _store_to_stack(
526
526
  self, stack_offset, data: RichR[claripy.ast.BV | claripy.ast.FP], size, offset=0, atom=None, endness=None
527
527
  ):
528
+ """
529
+ Store data to a stack location. We limit the size of the data to store to 256 bytes for performance reasons.
530
+ """
531
+
528
532
  if atom is None:
529
533
  existing_vars = self.state.variable_manager[self.func_addr].find_variables_by_stmt(
530
534
  self.block.addr, self.stmt_idx, "memory"
@@ -550,7 +554,11 @@ class SimEngineVRBase(
550
554
  variable, variable_offset = next(iter(existing_vars))
551
555
 
552
556
  if isinstance(stack_offset, int):
553
- expr = self.state.annotate_with_variables(data.data, [(variable_offset, variable)])
557
+ expr = data.data
558
+ if isinstance(expr, claripy.ast.Bits) and expr.size() > 1024:
559
+ # we don't write more than 256 bytes to the stack at a time for performance reasons
560
+ expr = expr[expr.size() - 1 : expr.size() - 1024]
561
+ expr = self.state.annotate_with_variables(expr, [(variable_offset, variable)])
554
562
  stack_addr = self.state.stack_addr_from_offset(stack_offset)
555
563
  self.state.stack_region.store(stack_addr, expr, endness=endness)
556
564
 
@@ -5,6 +5,8 @@ from collections.abc import Generator, Iterable
5
5
  import logging
6
6
  from collections import defaultdict
7
7
 
8
+ import networkx
9
+
8
10
  import archinfo
9
11
  import claripy
10
12
  from claripy.annotation import Annotation
@@ -86,8 +88,18 @@ class VariableRecoveryBase(Analysis):
86
88
  The base class for VariableRecovery and VariableRecoveryFast.
87
89
  """
88
90
 
89
- def __init__(self, func, max_iterations, store_live_variables: bool, vvar_to_vvar: dict[int, int] | None = None):
91
+ def __init__(
92
+ self,
93
+ func,
94
+ max_iterations,
95
+ store_live_variables: bool,
96
+ vvar_to_vvar: dict[int, int] | None = None,
97
+ func_graph: networkx.DiGraph | None = None,
98
+ entry_node_addr: int | tuple[int, int | None] | None = None,
99
+ ):
90
100
  self.function = func
101
+ self.func_graph = func_graph
102
+ self.entry_node_addr = entry_node_addr
91
103
  self.variable_manager = self.kb.variables
92
104
 
93
105
  self._max_iterations = max_iterations
@@ -120,7 +132,23 @@ class VariableRecoveryBase(Analysis):
120
132
 
121
133
  def initialize_dominance_frontiers(self):
122
134
  # Computer the dominance frontier for each node in the graph
123
- df = self.project.analyses.DominanceFrontier(self.function)
135
+ func_entry = None
136
+ if self.func_graph is not None:
137
+ entry_node_addr = self.entry_node_addr if self.entry_node_addr is not None else self.function.addr
138
+ assert entry_node_addr is not None
139
+ if isinstance(entry_node_addr, int):
140
+ func_entry = next(iter(node for node in self.func_graph if node.addr == entry_node_addr))
141
+ elif isinstance(entry_node_addr, tuple):
142
+ func_entry = next(
143
+ iter(
144
+ node
145
+ for node in self.func_graph
146
+ if node.addr == entry_node_addr[0] and node.idx == entry_node_addr[1]
147
+ )
148
+ )
149
+ else:
150
+ raise TypeError(f"Unsupported entry node address type: {type(entry_node_addr)}")
151
+ df = self.project.analyses.DominanceFrontier(self.function, func_graph=self.func_graph, entry=func_entry)
124
152
  self._dominance_frontiers = defaultdict(set)
125
153
  for b0, domfront in df.frontiers.items():
126
154
  for d in domfront:
@@ -237,6 +237,7 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
237
237
  self,
238
238
  func: Function | str | int,
239
239
  func_graph: networkx.DiGraph | None = None,
240
+ entry_node_addr: int | tuple[int, int | None] | None = None,
240
241
  max_iterations: int = 2,
241
242
  low_priority=False,
242
243
  track_sp=True,
@@ -259,10 +260,18 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
259
260
  function_graph_visitor = visitors.FunctionGraphVisitor(func, graph=func_graph)
260
261
 
261
262
  # Make sure the function is not empty
262
- if not func.block_addrs_set or func.startpoint is None:
263
+ if (not func.block_addrs_set or func.startpoint is None) and not func_graph:
263
264
  raise AngrVariableRecoveryError(f"Function {func!r} is empty.")
264
265
 
265
- VariableRecoveryBase.__init__(self, func, max_iterations, store_live_variables, vvar_to_vvar=vvar_to_vvar)
266
+ VariableRecoveryBase.__init__(
267
+ self,
268
+ func,
269
+ max_iterations,
270
+ store_live_variables,
271
+ vvar_to_vvar=vvar_to_vvar,
272
+ func_graph=func_graph_with_calls,
273
+ entry_node_addr=entry_node_addr,
274
+ )
266
275
  ForwardAnalysis.__init__(
267
276
  self, order_jobs=True, allow_merging=True, allow_widening=False, graph_visitor=function_graph_visitor
268
277
  )
angr/emulator.py ADDED
@@ -0,0 +1,143 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from enum import Enum
5
+
6
+ from angr.engines.concrete import ConcreteEngine, HeavyConcreteState
7
+ from angr.errors import AngrError
8
+
9
+
10
+ log = logging.getLogger(name=__name__)
11
+
12
+
13
+ class EmulatorException(AngrError):
14
+ """Base class for exceptions raised by the Emulator."""
15
+
16
+
17
+ class EngineException(EmulatorException):
18
+ """Exception raised when the emulator encounters an unhandlable error in the engine."""
19
+
20
+
21
+ class StateDivergedException(EmulatorException):
22
+ """Exception raised when an engine returns multiple successors."""
23
+
24
+
25
+ class EmulatorStopReason(Enum):
26
+ """
27
+ Enum representing the reason for stopping the emulator.
28
+ """
29
+
30
+ INSTRUCTION_LIMIT = "instruction_limit"
31
+ BREAKPOINT = "breakpoint"
32
+ NO_SUCCESSORS = "no_successors"
33
+ MEMORY_ERROR = "memory_error"
34
+ FAILURE = "failure"
35
+ EXIT = "exit"
36
+
37
+
38
+ class Emulator:
39
+ """
40
+ Emulator is a utility that adapts an angr `ConcreteEngine` to a more
41
+ user-friendly interface for concrete execution. It only supports concrete
42
+ execution and requires a ConcreteEngine.
43
+
44
+ Saftey: This class is not thread-safe. It should only be used in a
45
+ single-threaded context. It can be safely shared between multiple threads,
46
+ provided that only one thread is using it at a time.
47
+ """
48
+
49
+ _engine: ConcreteEngine
50
+ _state: HeavyConcreteState
51
+
52
+ def __init__(self, engine: ConcreteEngine, init_state: HeavyConcreteState):
53
+ """
54
+ :param engine: The `ConcreteEngine` to use for emulation.
55
+ :param init_state: The initial state to use for emulation.
56
+ """
57
+ self._engine = engine
58
+ self._state = init_state
59
+
60
+ @property
61
+ def state(self) -> HeavyConcreteState:
62
+ """
63
+ The current state of the emulator.
64
+ """
65
+ return self._state
66
+
67
+ @property
68
+ def breakpoints(self) -> set[int]:
69
+ """
70
+ The set of currently set breakpoints.
71
+ """
72
+ return self._engine.get_breakpoints()
73
+
74
+ def add_breakpoint(self, addr: int) -> None:
75
+ """
76
+ Add a breakpoint at the given address.
77
+
78
+ :param addr: The address to set the breakpoint at.
79
+ """
80
+ self._engine.add_breakpoint(addr)
81
+
82
+ def remove_breakpoint(self, addr: int) -> None:
83
+ """
84
+ Remove a breakpoint at the given address, if present.
85
+
86
+ :param addr: The address to remove the breakpoint from.
87
+ """
88
+ self._engine.remove_breakpoint(addr)
89
+
90
+ def run(self, num_inst: int | None = None) -> EmulatorStopReason:
91
+ """
92
+ Execute the emulator.
93
+ """
94
+ completed_engine_execs = 0
95
+ num_inst_executed: int = 0
96
+ while self._state.history.jumpkind != "Ijk_Exit":
97
+ # Check if there is a breakpoint at the current address
98
+ if completed_engine_execs > 0 and self._state.addr in self._engine.get_breakpoints():
99
+ return EmulatorStopReason.BREAKPOINT
100
+
101
+ # Check if we've already executed the requested number of instructions
102
+ if num_inst is not None and num_inst_executed >= num_inst:
103
+ return EmulatorStopReason.INSTRUCTION_LIMIT
104
+
105
+ # Calculate remaining instructions for this engine execution
106
+ remaining_inst: int | None = None
107
+ if num_inst is not None:
108
+ remaining_inst = num_inst - num_inst_executed
109
+
110
+ # Run the engine to get successors
111
+ try:
112
+ successors = self._engine.process(self._state, num_inst=remaining_inst)
113
+ except EngineException as e:
114
+ raise EngineException(f"Engine encountered an error: {e}") from e
115
+
116
+ # Handle cases with an unexpected number of successors
117
+ if len(successors.successors) == 0:
118
+ return EmulatorStopReason.NO_SUCCESSORS
119
+ if len(successors.successors) > 1:
120
+ log.warning("Concrete engine returned multiple successors")
121
+
122
+ # Set the state before raising further exceptions
123
+ self._state = successors.successors[0]
124
+
125
+ # Track the number of instructions executed using the state's history
126
+ if self._state.history.recent_instruction_count > 0:
127
+ num_inst_executed += self._state.history.recent_instruction_count
128
+
129
+ if successors.successors[0].history.jumpkind == "Ijk_SigSEGV":
130
+ return EmulatorStopReason.MEMORY_ERROR
131
+
132
+ completed_engine_execs += 1
133
+
134
+ return EmulatorStopReason.EXIT
135
+
136
+
137
+ __all__ = (
138
+ "Emulator",
139
+ "EmulatorException",
140
+ "EmulatorStopReason",
141
+ "EngineException",
142
+ "StateDivergedException",
143
+ )
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import typing
5
+ from abc import abstractmethod, ABCMeta
6
+ from typing_extensions import override
7
+
8
+ import claripy
9
+ from angr.engines.successors import SimSuccessors, SuccessorsEngine
10
+ from angr.sim_state import SimState
11
+
12
+ log = logging.getLogger(__name__)
13
+
14
+
15
+ HeavyConcreteState = SimState[int, int]
16
+
17
+
18
+ class ConcreteEngine(SuccessorsEngine, metaclass=ABCMeta):
19
+ """
20
+ ConcreteEngine extends SuccessorsEngine and adds APIs for managing breakpoints.
21
+ """
22
+
23
+ @abstractmethod
24
+ def get_breakpoints(self) -> set[int]:
25
+ """Return the set of currently set breakpoints."""
26
+
27
+ @abstractmethod
28
+ def add_breakpoint(self, addr: int) -> None:
29
+ """Add a breakpoint at the given address."""
30
+
31
+ @abstractmethod
32
+ def remove_breakpoint(self, addr: int) -> None:
33
+ """Remove a breakpoint at the given address, if present."""
34
+
35
+ @abstractmethod
36
+ def process_concrete(self, state: HeavyConcreteState, num_inst: int | None = None) -> HeavyConcreteState:
37
+ """
38
+ Process the concrete state and return a HeavyState object.
39
+
40
+ :param state: The concrete state to process.
41
+ :return: A HeavyState object representing the processed state.
42
+ """
43
+
44
+ @override
45
+ def process_successors(
46
+ self, successors: SimSuccessors, *, num_inst: int | None = None, **kwargs: dict[str, typing.Any]
47
+ ):
48
+ if len(kwargs) > 0:
49
+ log.warning("ConcreteEngine.process_successors received unknown kwargs: %s", kwargs)
50
+
51
+ # TODO: Properly error here when the state is not a HeavyConcreteState
52
+ # Alternatively, we could make SimSuccessors generic over the state type too
53
+ concrete_state = typing.cast(HeavyConcreteState, self.state)
54
+
55
+ concrete_successor = self.process_concrete(concrete_state, num_inst=num_inst)
56
+ successors.add_successor(
57
+ concrete_successor,
58
+ concrete_successor.ip,
59
+ claripy.true(),
60
+ concrete_successor.history.jumpkind,
61
+ add_guard=False,
62
+ )
63
+ successors.processed = True
64
+
65
+
66
+ __all__ = ["ConcreteEngine", "HeavyConcreteState"]
angr/engines/icicle.py CHANGED
@@ -5,17 +5,16 @@ from __future__ import annotations
5
5
  import logging
6
6
  import os
7
7
  from dataclasses import dataclass
8
+ from typing_extensions import override
8
9
 
9
- import claripy
10
10
  import pypcode
11
11
  from archinfo import Arch, Endness
12
12
 
13
+ from angr.engines.concrete import ConcreteEngine, HeavyConcreteState
13
14
  from angr.engines.failure import SimEngineFailure
14
15
  from angr.engines.hook import HooksMixin
15
- from angr.engines.successors import SuccessorsEngine
16
16
  from angr.engines.syscall import SimEngineSyscall
17
17
  from angr.rustylib.icicle import Icicle, VmExit, ExceptionCode
18
- from angr.sim_state import SimState
19
18
 
20
19
  log = logging.getLogger(__name__)
21
20
 
@@ -30,12 +29,13 @@ class IcicleStateTranslationData:
30
29
  to an angr state.
31
30
  """
32
31
 
33
- base_state: SimState
32
+ base_state: HeavyConcreteState
34
33
  registers: set[str]
35
34
  writable_pages: set[int]
35
+ initial_cpu_icount: int
36
36
 
37
37
 
38
- class IcicleEngine(SuccessorsEngine):
38
+ class IcicleEngine(ConcreteEngine):
39
39
  """
40
40
  An angr engine that uses Icicle to execute concrete states. The purpose of
41
41
  this implementation is to provide a high-performance concrete execution
@@ -55,6 +55,16 @@ class IcicleEngine(SuccessorsEngine):
55
55
  intends to provide a more complete set of features, such as hooks and syscalls.
56
56
  """
57
57
 
58
+ breakpoints: set[int]
59
+
60
+ def __init__(self, *args, **kwargs):
61
+ """
62
+ Initialize the IcicleEngine. This sets up the breakpoints set and
63
+ initializes the parent class.
64
+ """
65
+ super().__init__(*args, **kwargs)
66
+ self.breakpoints = set()
67
+
58
68
  @staticmethod
59
69
  def __make_icicle_arch(arch: Arch) -> str | None:
60
70
  """
@@ -81,7 +91,7 @@ class IcicleEngine(SuccessorsEngine):
81
91
  return IcicleEngine.__is_arm(icicle_arch) and addr & 1 == 1
82
92
 
83
93
  @staticmethod
84
- def __get_pages(state: SimState) -> set[int]:
94
+ def __get_pages(state: HeavyConcreteState) -> set[int]:
85
95
  """
86
96
  Unfortunately, the memory model doesn't have a way to get all pages.
87
97
  Instead, we can get all of the backers from the loader, then all of the
@@ -104,7 +114,7 @@ class IcicleEngine(SuccessorsEngine):
104
114
  return pages
105
115
 
106
116
  @staticmethod
107
- def __convert_angr_state_to_icicle(state: SimState) -> tuple[Icicle, IcicleStateTranslationData]:
117
+ def __convert_angr_state_to_icicle(state: HeavyConcreteState) -> tuple[Icicle, IcicleStateTranslationData]:
108
118
  icicle_arch = IcicleEngine.__make_icicle_arch(state.arch)
109
119
  if icicle_arch is None:
110
120
  raise ValueError("Unsupported architecture")
@@ -161,12 +171,15 @@ class IcicleEngine(SuccessorsEngine):
161
171
  base_state=state,
162
172
  registers=copied_registers,
163
173
  writable_pages=writable_pages,
174
+ initial_cpu_icount=emu.cpu_icount,
164
175
  )
165
176
 
166
177
  return (emu, translation_data)
167
178
 
168
179
  @staticmethod
169
- def __convert_icicle_state_to_angr(emu: Icicle, translation_data: IcicleStateTranslationData) -> SimState:
180
+ def __convert_icicle_state_to_angr(
181
+ emu: Icicle, translation_data: IcicleStateTranslationData, status: VmExit
182
+ ) -> HeavyConcreteState:
170
183
  state = translation_data.base_state.copy()
171
184
 
172
185
  # 1. Copy the register values
@@ -181,20 +194,8 @@ class IcicleEngine(SuccessorsEngine):
181
194
  addr = page_num * state.memory.page_size
182
195
  state.memory.store(addr, emu.mem_read(addr, state.memory.page_size))
183
196
 
184
- return state
185
-
186
- def process_successors(self, successors, *, num_inst=0, **kwargs):
187
- if len(kwargs) > 0:
188
- log.warning("IcicleEngine.process_successors received unknown kwargs: %s", kwargs)
189
-
190
- emu, translation_data = self.__convert_angr_state_to_icicle(self.state)
191
-
192
- if num_inst > 0:
193
- emu.icount_limit = num_inst
194
-
195
- status = emu.run() # pylint: ignore=assignment-from-no-return (pylint bug)
197
+ # 3. Set history.jumpkind
196
198
  exc = emu.exception_code
197
-
198
199
  if status == VmExit.UnhandledException:
199
200
  if exc in (
200
201
  ExceptionCode.ReadUnmapped,
@@ -203,22 +204,57 @@ class IcicleEngine(SuccessorsEngine):
203
204
  ExceptionCode.WritePerm,
204
205
  ExceptionCode.ExecViolation,
205
206
  ):
206
- jumpkind = "Ijk_SigSEGV"
207
+ state.history.jumpkind = "Ijk_SigSEGV"
207
208
  elif exc == ExceptionCode.Syscall:
208
- jumpkind = "Ijk_Syscall"
209
+ state.history.jumpkind = "Ijk_Syscall"
209
210
  elif exc == ExceptionCode.Halt:
210
- jumpkind = "Ijk_Exit"
211
+ state.history.jumpkind = "Ijk_Exit"
211
212
  elif exc == ExceptionCode.InvalidInstruction:
212
- jumpkind = "Ijk_NoDecode"
213
+ state.history.jumpkind = "Ijk_NoDecode"
213
214
  else:
214
- jumpkind = "Ijk_EmFail"
215
+ state.history.jumpkind = "Ijk_EmFail"
215
216
  else:
216
- jumpkind = "Ijk_Boring"
217
+ state.history.jumpkind = "Ijk_Boring"
218
+
219
+ # 4. Set history.recent_instruction_count
220
+ state.history.recent_instruction_count = emu.cpu_icount - translation_data.initial_cpu_icount
221
+
222
+ return state
223
+
224
+ @override
225
+ def get_breakpoints(self) -> set[int]:
226
+ """Return the set of currently set breakpoints."""
227
+ return self.breakpoints
228
+
229
+ @override
230
+ def add_breakpoint(self, addr: int) -> None:
231
+ """Add a breakpoint at the given address."""
232
+ self.breakpoints.add(addr)
233
+
234
+ @override
235
+ def remove_breakpoint(self, addr: int) -> None:
236
+ """Remove a breakpoint at the given address, if present."""
237
+ self.breakpoints.discard(addr)
238
+
239
+ @override
240
+ def process_concrete(self, state: HeavyConcreteState, num_inst: int | None = None) -> HeavyConcreteState:
241
+ emu, translation_data = self.__convert_angr_state_to_icicle(state)
242
+
243
+ # Set breakpoints, skip the current PC. This assumes that if running
244
+ # with a breakpoint at the current PC, then the user has already done
245
+ # the necessary handling and is resuming execution.
246
+ for addr in self.breakpoints:
247
+ if emu.pc != addr:
248
+ emu.add_breakpoint(addr)
249
+
250
+ # Set the instruction count limit
251
+ if num_inst is not None and num_inst > 0:
252
+ emu.icount_limit = num_inst
217
253
 
218
- successor_state = IcicleEngine.__convert_icicle_state_to_angr(emu, translation_data)
219
- successors.add_successor(successor_state, successor_state.ip, claripy.true(), jumpkind, add_guard=False)
254
+ # Run it
255
+ status = emu.run()
220
256
 
221
- successors.processed = True
257
+ return IcicleEngine.__convert_icicle_state_to_angr(emu, translation_data, status)
222
258
 
223
259
 
224
260
  class UberIcicleEngine(SimEngineFailure, SimEngineSyscall, HooksMixin, IcicleEngine):
@@ -94,7 +94,7 @@ class DrillerCore(ExplorationTechnique):
94
94
  @staticmethod
95
95
  def _has_false(state):
96
96
  # Check if the state is unsat even if we remove preconstraints.
97
- if state.scratch.guard.identical(claripy.false()):
97
+ if claripy.is_false(state.scratch.guard):
98
98
  return True
99
99
 
100
- return any(c.identical(claripy.false()) for c in state.solver.constraints)
100
+ return any(claripy.is_false(c) for c in state.solver.constraints)
angr/project.py CHANGED
@@ -297,11 +297,18 @@ class Project:
297
297
 
298
298
  # Step 1: get the set of libraries we are allowed to use to resolve unresolved symbols
299
299
  missing_libs = []
300
+ missing_wincore_dlls = False
300
301
  for lib_name in self.loader.missing_dependencies:
301
302
  try:
302
303
  missing_libs.extend(SIM_LIBRARIES[lib_name])
303
304
  except KeyError:
304
305
  l.info("There are no simprocedures for missing library %s :(", lib_name)
306
+ if lib_name.startswith("api-ms-win-"):
307
+ missing_wincore_dlls = True
308
+ if missing_wincore_dlls and "kernel32.dll" not in self.loader.missing_dependencies:
309
+ # some of the missing api-ms-win-*.dll libraries are actually provided by kernel32.dll
310
+ missing_libs.extend(SIM_LIBRARIES["kernel32.dll"])
311
+
305
312
  # additionally provide libraries we _have_ loaded as a fallback fallback
306
313
  # this helps in the case that e.g. CLE picked up a linux arm libc to satisfy an android arm binary
307
314
  for lib in self.loader.all_objects:
angr/rustylib.abi3.so CHANGED
Binary file
angr/sim_type.py CHANGED
@@ -609,33 +609,41 @@ class SimTypeWideChar(SimTypeReg):
609
609
 
610
610
  _base_name = "char"
611
611
 
612
- def __init__(self, signed=True, label=None):
612
+ def __init__(self, signed=True, label=None, endness: Endness = Endness.BE):
613
613
  """
614
614
  :param label: the type label.
615
615
  """
616
616
  SimTypeReg.__init__(self, 16, label=label)
617
617
  self.signed = signed
618
+ self.endness = endness
618
619
 
619
620
  def __repr__(self):
620
621
  return "wchar"
621
622
 
622
623
  def store(self, state, addr, value: StoreType):
623
- self._size = state.arch.byte_width
624
624
  try:
625
625
  super().store(state, addr, value)
626
626
  except TypeError:
627
627
  if isinstance(value, bytes) and len(value) == 2:
628
- value = claripy.BVV(value[0], state.arch.byte_width)
628
+ inner = (
629
+ ((value[0] << state.arch.byte_width) | value[1])
630
+ if self.endness == Endness.BE
631
+ else ((value[1] << state.arch.byte_width) | value[0])
632
+ )
633
+ value = claripy.BVV(inner, state.arch.byte_width * 2)
629
634
  super().store(state, addr, value)
630
635
  else:
631
636
  raise
632
637
 
633
638
  def extract(self, state, addr, concrete=False) -> Any:
634
- self._size = state.arch.byte_width
635
-
636
- out = super().extract(state, addr, concrete)
639
+ out = state.memory.load(addr, 2)
637
640
  if concrete:
638
- return bytes([out])
641
+ data = state.solver.eval(out, cast_to=bytes)
642
+ fmt_str = "utf-16be" if self.endness == Endness.BE else "utf-16le"
643
+ try:
644
+ return data.decode(fmt_str)
645
+ except UnicodeDecodeError:
646
+ return data
639
647
  return out
640
648
 
641
649
  def _init_str(self):
@@ -645,7 +653,7 @@ class SimTypeWideChar(SimTypeReg):
645
653
  )
646
654
 
647
655
  def copy(self):
648
- return self.__class__(signed=self.signed, label=self.label)
656
+ return self.__class__(signed=self.signed, label=self.label, endness=self.endness)
649
657
 
650
658
 
651
659
  class SimTypeBool(SimTypeReg):
@@ -394,14 +394,14 @@ class _VexArchInfo(ctypes.Structure):
394
394
 
395
395
  def _load_native():
396
396
  if sys.platform == "darwin":
397
- libfile = "angr_native.dylib"
397
+ libfile = "unicornlib.dylib"
398
398
  elif sys.platform in {"win32", "cygwin"}:
399
- libfile = "angr_native.dll"
399
+ libfile = "unicornlib.dll"
400
400
  else:
401
- libfile = "angr_native.so"
401
+ libfile = "unicornlib.so"
402
402
 
403
403
  try:
404
- angr_path = str(importlib.resources.files("angr") / "lib" / libfile)
404
+ angr_path = str(importlib.resources.files("angr") / libfile)
405
405
  h = ctypes.CDLL(angr_path)
406
406
 
407
407
  VexArch = ctypes.c_int
angr/utils/graph.py CHANGED
@@ -534,11 +534,30 @@ class Dominators:
534
534
 
535
535
  def _pd_eval(self, v):
536
536
  assert self._ancestor is not None
537
+ assert self._semi is not None
537
538
  assert self._label is not None
538
539
 
539
540
  if self._ancestor[v.index] is None:
540
541
  return v
541
- self._pd_compress(v)
542
+
543
+ # pd_compress without recursion
544
+ queue = []
545
+ current = v
546
+ ancestor = self._ancestor[current.index]
547
+ greater_ancestor = self._ancestor[ancestor.index]
548
+ while greater_ancestor is not None:
549
+ queue.append(current)
550
+ current, ancestor = ancestor, greater_ancestor
551
+ greater_ancestor = self._ancestor[ancestor.index]
552
+
553
+ for vv in reversed(queue):
554
+ if (
555
+ self._semi[self._label[self._ancestor[vv.index].index].index].index
556
+ < self._semi[self._label[vv.index].index].index
557
+ ):
558
+ self._label[vv.index] = self._label[self._ancestor[vv.index].index]
559
+ self._ancestor[vv.index] = self._ancestor[self._ancestor[vv.index].index]
560
+
542
561
  return self._label[v.index]
543
562
 
544
563
  def _pd_compress(self, v):
@@ -89,7 +89,7 @@ def get_reg_offset_base(reg_offset, arch, size=None, resilient=True):
89
89
 
90
90
 
91
91
  def get_vvar_deflocs(
92
- blocks, phi_vvars: dict[int, set[int]] | None = None
92
+ blocks, phi_vvars: dict[int, set[int | None]] | None = None
93
93
  ) -> dict[int, tuple[VirtualVariable, CodeLocation]]:
94
94
  vvar_to_loc: dict[int, tuple[VirtualVariable, CodeLocation]] = {}
95
95
  for block in blocks:
@@ -100,7 +100,7 @@ def get_vvar_deflocs(
100
100
  )
101
101
  if phi_vvars is not None and isinstance(stmt.src, Phi):
102
102
  phi_vvars[stmt.dst.varid] = {
103
- vvar_.varid for src, vvar_ in stmt.src.src_and_vvars if vvar_ is not None
103
+ vvar_.varid if vvar_ is not None else None for src, vvar_ in stmt.src.src_and_vvars
104
104
  }
105
105
  elif isinstance(stmt, Call):
106
106
  if isinstance(stmt.ret_expr, VirtualVariable):
@@ -161,7 +161,7 @@ def get_tmp_uselocs(blocks) -> dict[CodeLocation, dict[atoms.Tmp, set[tuple[Tmp,
161
161
  return tmp_to_loc
162
162
 
163
163
 
164
- def is_const_assignment(stmt: Statement) -> tuple[bool, Const | None]:
164
+ def is_const_assignment(stmt: Statement) -> tuple[bool, Const | StackBaseOffset | None]:
165
165
  if isinstance(stmt, Assignment) and isinstance(stmt.src, (Const, StackBaseOffset)):
166
166
  return True, stmt.src
167
167
  return False, None