angr 9.2.79__py3-none-win_amd64.whl → 9.2.80__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 (40) hide show
  1. angr/__init__.py +1 -1
  2. angr/__main__.py +30 -5
  3. angr/analyses/cfg/cfg_fast.py +128 -3
  4. angr/analyses/decompiler/ail_simplifier.py +8 -0
  5. angr/analyses/decompiler/clinic.py +6 -2
  6. angr/analyses/decompiler/decompilation_options.py +9 -0
  7. angr/analyses/decompiler/optimization_passes/__init__.py +4 -0
  8. angr/analyses/decompiler/optimization_passes/multi_simplifier.py +0 -12
  9. angr/analyses/decompiler/optimization_passes/optimization_pass.py +8 -5
  10. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +2 -25
  11. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +14 -2
  12. angr/analyses/decompiler/region_simplifiers/ifelse.py +19 -10
  13. angr/analyses/decompiler/region_simplifiers/region_simplifier.py +4 -2
  14. angr/analyses/decompiler/utils.py +8 -5
  15. angr/analyses/propagator/engine_ail.py +3 -1
  16. angr/analyses/propagator/engine_vex.py +45 -0
  17. angr/analyses/propagator/propagator.py +24 -15
  18. angr/analyses/reaching_definitions/engine_ail.py +1 -1
  19. angr/analyses/stack_pointer_tracker.py +55 -0
  20. angr/callable.py +4 -4
  21. angr/engines/light/engine.py +30 -18
  22. angr/knowledge_plugins/propagations/propagation_model.py +4 -0
  23. angr/knowledge_plugins/propagations/states.py +54 -4
  24. angr/lib/angr_native.dll +0 -0
  25. angr/procedures/definitions/__init__.py +2 -1
  26. angr/procedures/definitions/ntoskrnl.py +9 -0
  27. angr/procedures/win32_kernel/ExAllocatePool.py +12 -0
  28. angr/procedures/win32_kernel/ExFreePoolWithTag.py +7 -0
  29. angr/procedures/win32_kernel/__init__.py +3 -0
  30. angr/storage/memory_mixins/__init__.py +1 -1
  31. angr/utils/funcid.py +128 -0
  32. {angr-9.2.79.dist-info → angr-9.2.80.dist-info}/METADATA +6 -6
  33. {angr-9.2.79.dist-info → angr-9.2.80.dist-info}/RECORD +40 -35
  34. tests/analyses/cfg/test_cfgfast.py +24 -0
  35. tests/analyses/decompiler/test_decompiler.py +128 -0
  36. tests/analyses/test_constantpropagation.py +34 -0
  37. {angr-9.2.79.dist-info → angr-9.2.80.dist-info}/LICENSE +0 -0
  38. {angr-9.2.79.dist-info → angr-9.2.80.dist-info}/WHEEL +0 -0
  39. {angr-9.2.79.dist-info → angr-9.2.80.dist-info}/entry_points.txt +0 -0
  40. {angr-9.2.79.dist-info → angr-9.2.80.dist-info}/top_level.txt +0 -0
@@ -289,6 +289,9 @@ class PropagatorAnalysis(ForwardAnalysis, Analysis): # pylint:disable=abstract-
289
289
  if self._base_state is not None:
290
290
  self._base_state.options.add(sim_options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS)
291
291
  self._base_state.options.add(sim_options.SYMBOL_FILL_UNCONSTRAINED_MEMORY)
292
+
293
+ self.model.input_states[block_key] = state.copy()
294
+
292
295
  state = engine.process(
293
296
  state,
294
297
  block=block,
@@ -305,8 +308,7 @@ class PropagatorAnalysis(ForwardAnalysis, Analysis): # pylint:disable=abstract-
305
308
 
306
309
  self.model.node_iterations[block_key] += 1
307
310
  self.model.states[block_key] = state
308
- if isinstance(state, PropagatorAILState):
309
- self.model.block_initial_reg_values.update(state.block_initial_reg_values)
311
+ self.model.block_initial_reg_values.update(state.block_initial_reg_values)
310
312
 
311
313
  if self.model.replacements is None:
312
314
  self.model.replacements = state._replacements
@@ -325,19 +327,26 @@ class PropagatorAnalysis(ForwardAnalysis, Analysis): # pylint:disable=abstract-
325
327
  def _process_input_state_for_successor(
326
328
  self, node, successor, input_state: Union[PropagatorAILState, PropagatorVEXState]
327
329
  ):
328
- if self._only_consts and isinstance(input_state, PropagatorAILState):
329
- key = node.addr, successor.addr
330
- if key in self.model.block_initial_reg_values:
331
- input_state: PropagatorAILState = input_state.copy()
332
- for reg_atom, reg_value in self.model.block_initial_reg_values[key]:
333
- input_state.store_register(
334
- reg_atom,
335
- PropValue(
336
- claripy.BVV(reg_value.value, reg_value.bits),
337
- offset_and_details={0: Detail(reg_atom.size, reg_value, self._initial_codeloc)},
338
- ),
339
- )
340
- return input_state
330
+ if self._only_consts:
331
+ if isinstance(input_state, PropagatorAILState):
332
+ key = node.addr, successor.addr
333
+ if key in self.model.block_initial_reg_values:
334
+ input_state: PropagatorAILState = input_state.copy()
335
+ for reg_atom, reg_value in self.model.block_initial_reg_values[key]:
336
+ input_state.store_register(
337
+ reg_atom,
338
+ PropValue(
339
+ claripy.BVV(reg_value.value, reg_value.bits),
340
+ offset_and_details={0: Detail(reg_atom.size, reg_value, self._initial_codeloc)},
341
+ ),
342
+ )
343
+ return input_state
344
+ elif isinstance(input_state, PropagatorVEXState):
345
+ key = node.addr, successor.addr
346
+ if key in self.model.block_initial_reg_values:
347
+ input_state: PropagatorVEXState = input_state.copy()
348
+ for reg_offset, reg_size, value in self.model.block_initial_reg_values[key]:
349
+ input_state.store_register(reg_offset, reg_size, claripy.BVV(value, reg_size * 8))
341
350
  return input_state
342
351
 
343
352
  def _intra_analysis(self):
@@ -141,7 +141,7 @@ class SimEngineRDAIL(
141
141
  return handler(expr)
142
142
  else:
143
143
  self.l.warning("Unsupported expression type %s.", type(expr).__name__)
144
- return None
144
+ return MultiValues(self.state.top(self.arch.bits))
145
145
 
146
146
  def _ail_handle_Assignment(self, stmt):
147
147
  """
@@ -1,6 +1,7 @@
1
1
  # pylint:disable=abstract-method,ungrouped-imports
2
2
 
3
3
  from typing import Set, List, Optional, TYPE_CHECKING
4
+ import re
4
5
  import logging
5
6
 
6
7
  import pyvex
@@ -286,6 +287,9 @@ class CouldNotResolveException(Exception):
286
287
  """
287
288
 
288
289
 
290
+ IROP_CONVERT_REGEX = re.compile(r"^Iop_(\d+)(U{0,1})to(\d+)(U{0,1})$")
291
+
292
+
289
293
  class StackPointerTracker(Analysis, ForwardAnalysis):
290
294
  """
291
295
  Track the offset of stack pointer at the end of each basic block of a function.
@@ -366,6 +370,42 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
366
370
  else:
367
371
  return self.offset_before(instr_addrs[0], reg)
368
372
 
373
+ def _constant_for(self, addr, pre_or_post, reg):
374
+ try:
375
+ s = self._state_for(addr, pre_or_post)
376
+ if s is None:
377
+ return TOP
378
+ regval = dict(s.regs)[reg]
379
+ except KeyError:
380
+ return TOP
381
+ if type(regval) is Constant:
382
+ return regval.val
383
+ return TOP
384
+
385
+ def constant_after(self, addr, reg):
386
+ return self._constant_for(addr, "post", reg)
387
+
388
+ def constant_before(self, addr, reg):
389
+ return self._constant_for(addr, "pre", reg)
390
+
391
+ def constant_after_block(self, block_addr, reg):
392
+ if block_addr not in self._blocks:
393
+ return TOP
394
+ instr_addrs = self._blocks[block_addr].instruction_addrs
395
+ if len(instr_addrs) == 0:
396
+ return TOP
397
+ else:
398
+ return self.constant_after(instr_addrs[-1], reg)
399
+
400
+ def constant_before_block(self, block_addr, reg):
401
+ if block_addr not in self._blocks:
402
+ return TOP
403
+ instr_addrs = self._blocks[block_addr].instruction_addrs
404
+ if len(instr_addrs) == 0:
405
+ return TOP
406
+ else:
407
+ return self.constant_before(instr_addrs[0], reg)
408
+
369
409
  @property
370
410
  def inconsistent(self):
371
411
  return any(self.inconsistent_for(r) for r in self.reg_offsets)
@@ -515,6 +555,21 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
515
555
  return Constant(expr.con.value)
516
556
  elif type(expr) is pyvex.IRExpr.Get:
517
557
  return state.get(expr.offset)
558
+ elif type(expr) is pyvex.IRExpr.Unop:
559
+ m = IROP_CONVERT_REGEX.match(expr.op)
560
+ if m is not None:
561
+ from_bits = int(m.group(1))
562
+ # from_unsigned = m.group(2) == "U"
563
+ to_bits = int(m.group(3))
564
+ # to_unsigned = m.group(4) == "U"
565
+ v = resolve_expr(expr.args[0])
566
+ if not isinstance(v, Constant):
567
+ return TOP
568
+ if from_bits > to_bits:
569
+ # truncation
570
+ mask = (1 << to_bits) - 1
571
+ return Constant(v.val & mask)
572
+ return v
518
573
  elif self.track_mem and type(expr) is pyvex.IRExpr.Load:
519
574
  return state.load(_resolve_expr(expr.addr))
520
575
  raise CouldNotResolveException()
angr/callable.py CHANGED
@@ -74,10 +74,10 @@ class Callable:
74
74
  self.perform_call(*args, prototype=prototype)
75
75
  if self.result_state is not None and prototype.returnty is not None:
76
76
  loc = self._cc.return_val(prototype.returnty)
77
- val = loc.get_value(self.result_state, stack_base=self.result_state.regs.sp - self._cc.STACKARG_SP_DIFF)
78
- return self.result_state.solver.simplify(val)
79
- else:
80
- return None
77
+ if loc is not None:
78
+ val = loc.get_value(self.result_state, stack_base=self.result_state.regs.sp - self._cc.STACKARG_SP_DIFF)
79
+ return self.result_state.solver.simplify(val)
80
+ return None
81
81
 
82
82
  def perform_call(self, *args, prototype=None):
83
83
  prototype = SimCC.guess_prototype(args, prototype or self._func_ty).with_arch(self._project.arch)
@@ -177,12 +177,12 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
177
177
  func_addr = (
178
178
  self.block.vex.next if isinstance(self.block.vex.next, int) else self._expr(self.block.vex.next)
179
179
  )
180
- if func_addr is not None:
181
- getattr(self, handler)(func_addr)
182
- else:
180
+ if func_addr is None and self.l is not None:
183
181
  self.l.debug("Cannot determine the callee address at %#x.", self.block.addr)
182
+ getattr(self, handler)(func_addr)
184
183
  else:
185
- self.l.warning("Function handler not implemented.")
184
+ if self.l is not None:
185
+ self.l.warning("Function handler not implemented.")
186
186
 
187
187
  #
188
188
  # Statement handlers
@@ -193,7 +193,8 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
193
193
  if hasattr(self, handler):
194
194
  getattr(self, handler)(stmt)
195
195
  elif type(stmt).__name__ not in ("IMark", "AbiHint"):
196
- self.l.error("Unsupported statement type %s.", type(stmt).__name__)
196
+ if self.l is not None:
197
+ self.l.error("Unsupported statement type %s.", type(stmt).__name__)
197
198
 
198
199
  # synchronize with function _handle_WrTmpData()
199
200
  def _handle_WrTmp(self, stmt):
@@ -210,7 +211,8 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
210
211
  self.tmps[tmp] = data
211
212
 
212
213
  def _handle_Dirty(self, stmt):
213
- self.l.error("Unimplemented Dirty node for current architecture.")
214
+ if self.l is not None:
215
+ self.l.error("Unimplemented Dirty node for current architecture.")
214
216
 
215
217
  def _handle_Put(self, stmt):
216
218
  raise NotImplementedError("Please implement the Put handler with your own logic.")
@@ -232,12 +234,13 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
232
234
  handler = "_handle_%s" % type(expr).__name__
233
235
  if hasattr(self, handler):
234
236
  return getattr(self, handler)(expr)
235
- else:
237
+ elif self.l is not None:
236
238
  self.l.error("Unsupported expression type %s.", type(expr).__name__)
237
239
  return None
238
240
 
239
241
  def _handle_Triop(self, expr: pyvex.IRExpr.Triop): # pylint: disable=useless-return
240
- self.l.error("Unsupported Triop %s.", expr.op)
242
+ if self.l is not None:
243
+ self.l.error("Unsupported Triop %s.", expr.op)
241
244
  return None
242
245
 
243
246
  def _handle_RdTmp(self, expr):
@@ -295,7 +298,8 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
295
298
  if handler is not None and hasattr(self, handler):
296
299
  return getattr(self, handler)(expr)
297
300
  else:
298
- self.l.error("Unsupported Unop %s.", expr.op)
301
+ if self.l is not None:
302
+ self.l.error("Unsupported Unop %s.", expr.op)
299
303
  return None
300
304
 
301
305
  def _handle_Binop(self, expr: pyvex.IRExpr.Binop):
@@ -372,13 +376,14 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
372
376
  return getattr(self, handler)(expr, vector_size, vector_count)
373
377
  return getattr(self, handler)(expr)
374
378
  else:
375
- if once(expr.op):
379
+ if once(expr.op) and self.l is not None:
376
380
  self.l.warning("Unsupported Binop %s.", expr.op)
377
381
 
378
382
  return None
379
383
 
380
384
  def _handle_CCall(self, expr): # pylint:disable=useless-return
381
- self.l.warning("Unsupported expression type CCall with callee %s.", str(expr.cee))
385
+ if self.l is not None:
386
+ self.l.warning("Unsupported expression type CCall with callee %s.", str(expr.cee))
382
387
  return None
383
388
 
384
389
  #
@@ -479,7 +484,8 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
479
484
  try:
480
485
  return ~expr_0 # pylint:disable=invalid-unary-operand-type
481
486
  except TypeError as e:
482
- self.l.exception(e)
487
+ if self.l is not None:
488
+ self.l.exception(e)
483
489
  return None
484
490
 
485
491
  def _handle_Clz(self, expr):
@@ -602,7 +608,8 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
602
608
  try:
603
609
  return expr_0 ^ expr_1
604
610
  except TypeError as e:
605
- self.l.warning(e)
611
+ if self.l is not None:
612
+ self.l.warning(e)
606
613
  return None
607
614
 
608
615
  def _handle_Shl(self, expr):
@@ -834,7 +841,8 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
834
841
 
835
842
  if h is not None:
836
843
  return h(expr)
837
- self.l.warning("Unsupported expression type %s.", type(expr).__name__)
844
+ if self.l is not None:
845
+ self.l.warning("Unsupported expression type %s.", type(expr).__name__)
838
846
  return None
839
847
 
840
848
  #
@@ -866,7 +874,8 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
866
874
  getattr(self, old_handler)(stmt)
867
875
  return
868
876
 
869
- self.l.warning("Unsupported statement type %s.", type(stmt).__name__)
877
+ if self.l is not None:
878
+ self.l.warning("Unsupported statement type %s.", type(stmt).__name__)
870
879
 
871
880
  def _ail_handle_Label(self, stmt):
872
881
  pass
@@ -933,7 +942,8 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
933
942
  try:
934
943
  handler = getattr(self, handler_name)
935
944
  except AttributeError:
936
- self.l.warning("Unsupported UnaryOp %s.", expr.op)
945
+ if self.l is not None:
946
+ self.l.warning("Unsupported UnaryOp %s.", expr.op)
937
947
  return None
938
948
 
939
949
  return handler(expr)
@@ -943,7 +953,8 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
943
953
  try:
944
954
  handler = getattr(self, handler_name)
945
955
  except AttributeError:
946
- self.l.warning("Unsupported BinaryOp %s.", expr.op)
956
+ if self.l is not None:
957
+ self.l.warning("Unsupported BinaryOp %s.", expr.op)
947
958
  return None
948
959
 
949
960
  return handler(expr)
@@ -953,7 +964,8 @@ class SimEngineLightAILMixin(SimEngineLightMixin):
953
964
  try:
954
965
  handler = getattr(self, handler_name)
955
966
  except AttributeError:
956
- self.l.warning("Unsupported Ternary %s.", expr.op)
967
+ if self.l is not None:
968
+ self.l.warning("Unsupported Ternary %s.", expr.op)
957
969
  return None
958
970
 
959
971
  return handler(expr)
@@ -17,6 +17,7 @@ class PropagationModel(Serializable):
17
17
  "key",
18
18
  "node_iterations",
19
19
  "states",
20
+ "input_states",
20
21
  "block_initial_reg_values",
21
22
  "replacements",
22
23
  "equivalence",
@@ -35,9 +36,11 @@ class PropagationModel(Serializable):
35
36
  replacements: Optional[DefaultDict[Any, Dict]] = None,
36
37
  equivalence: Optional[Set] = None,
37
38
  function: Optional[Function] = None,
39
+ input_states: Optional[Dict] = None,
38
40
  ):
39
41
  self.key = prop_key
40
42
  self.node_iterations = node_iterations if node_iterations is not None else defaultdict(int)
43
+ self.input_states = input_states if input_states is not None else {}
41
44
  self.states = states if states is not None else {}
42
45
  self.block_initial_reg_values = block_initial_reg_values if block_initial_reg_values is not None else {}
43
46
  self.replacements = replacements
@@ -51,6 +54,7 @@ class PropagationModel(Serializable):
51
54
  self.node_iterations = None
52
55
  self.block_initial_reg_values = None
53
56
  self.states = None
57
+ self.input_states = None
54
58
  self.graph_visitor = None
55
59
 
56
60
  def block_beginning_state(self, block_addr) -> PropagatorState:
@@ -1,3 +1,4 @@
1
+ # pylint:disable=too-many-boolean-expressions
1
2
  from typing import Set, Optional, Union, Tuple, DefaultDict, List, Any, Dict, TYPE_CHECKING
2
3
  from collections import defaultdict
3
4
  import weakref
@@ -256,7 +257,9 @@ class PropagatorState:
256
257
  def init_replacements(self):
257
258
  self._replacements = defaultdict(dict)
258
259
 
259
- def add_replacement(self, codeloc: CodeLocation, old, new, force_replace: bool = False) -> bool:
260
+ def add_replacement(
261
+ self, codeloc: CodeLocation, old, new, force_replace: bool = False
262
+ ) -> bool: # pylint:disable=unused-argument
260
263
  """
261
264
  Add a replacement record: Replacing expression `old` with `new` at program location `codeloc`.
262
265
  If the self._only_consts flag is set to true, only constant values will be set.
@@ -296,6 +299,44 @@ class PropagatorState:
296
299
  # VEX state
297
300
 
298
301
 
302
+ class RegisterAnnotation(claripy.Annotation):
303
+ """
304
+ Annotates TOP values that are coming from registers.
305
+ """
306
+
307
+ def __init__(self, offset, size):
308
+ self.offset = offset
309
+ self.size = size
310
+
311
+ @property
312
+ def eliminatable(self) -> bool:
313
+ return True
314
+
315
+ @property
316
+ def relocatable(self) -> bool:
317
+ return True
318
+
319
+
320
+ class RegisterComparisonAnnotation(claripy.Annotation):
321
+ """
322
+ Annotate TOP values that are the result of register values comparing against constant values.
323
+ """
324
+
325
+ def __init__(self, offset, size, cmp_op, value):
326
+ self.offset = offset
327
+ self.size = size
328
+ self.cmp_op = cmp_op
329
+ self.value = value
330
+
331
+ @property
332
+ def eliminatable(self) -> bool:
333
+ return True
334
+
335
+ @property
336
+ def relocatable(self) -> bool:
337
+ return True
338
+
339
+
299
340
  class PropagatorVEXState(PropagatorState):
300
341
  """
301
342
  Describes the state used in the VEX engine of Propagator.
@@ -305,6 +346,7 @@ class PropagatorVEXState(PropagatorState):
305
346
  "_registers",
306
347
  "_stack_variables",
307
348
  "do_binops",
349
+ "block_initial_reg_values",
308
350
  )
309
351
 
310
352
  def __init__(
@@ -319,6 +361,7 @@ class PropagatorVEXState(PropagatorState):
319
361
  expr_used_locs=None,
320
362
  do_binops=True,
321
363
  store_tops=True,
364
+ block_initial_reg_values=None,
322
365
  gp=None,
323
366
  max_prop_expr_occurrence: int = 1,
324
367
  model=None,
@@ -349,6 +392,9 @@ class PropagatorVEXState(PropagatorState):
349
392
 
350
393
  self._registers.set_state(self)
351
394
  self._stack_variables.set_state(self)
395
+ self.block_initial_reg_values = (
396
+ defaultdict(list) if block_initial_reg_values is None else block_initial_reg_values
397
+ )
352
398
 
353
399
  def __repr__(self):
354
400
  return "<PropagatorVEXState>"
@@ -418,6 +464,7 @@ class PropagatorVEXState(PropagatorState):
418
464
  only_consts=self._only_consts,
419
465
  do_binops=self.do_binops,
420
466
  store_tops=self._store_tops,
467
+ block_initial_reg_values=self.block_initial_reg_values.copy(),
421
468
  gp=self._gp,
422
469
  max_prop_expr_occurrence=self._max_prop_expr_occurrence,
423
470
  model=self.model,
@@ -448,12 +495,15 @@ class PropagatorVEXState(PropagatorState):
448
495
  def load_register(self, offset, size):
449
496
  # TODO: Fix me
450
497
  if size != self.gpr_size:
451
- return self.top(size * self.arch.byte_width)
498
+ return self.top(size * self.arch.byte_width).annotate(RegisterAnnotation(offset, size))
452
499
 
453
500
  try:
454
- return self._registers.load(offset, size=size)
501
+ v = self._registers.load(offset, size=size)
502
+ if self.is_top(v):
503
+ v = v.annotate(RegisterAnnotation(offset, size))
504
+ return v
455
505
  except SimMemoryMissingError:
456
- return self.top(size * self.arch.byte_width)
506
+ return self.top(size * self.arch.byte_width).annotate(RegisterAnnotation(offset, size))
457
507
 
458
508
  def register_results(self) -> Dict[str, claripy.ast.BV]:
459
509
  result = {}
angr/lib/angr_native.dll CHANGED
Binary file
@@ -632,7 +632,8 @@ def load_win32api_definitions():
632
632
  for _ in autoimport.auto_import_modules(
633
633
  "angr.procedures.definitions",
634
634
  _DEFINITIONS_BASEDIR,
635
- filter_func=lambda module_name: module_name.startswith("win32_"),
635
+ filter_func=lambda module_name: module_name.startswith("win32_")
636
+ or module_name in {"ntoskrnl", "ntdll", "user32"},
636
637
  ):
637
638
  pass
638
639
 
@@ -0,0 +1,9 @@
1
+ from . import SimLibrary
2
+ from .. import SIM_PROCEDURES as P
3
+ from ...calling_conventions import SimCCStdcall, SimCCMicrosoftAMD64
4
+
5
+ lib = SimLibrary()
6
+ lib.set_library_names("ntoskrnl.exe")
7
+ lib.add_all_from_dict(P["win32_kernel"])
8
+ lib.set_default_cc("X86", SimCCStdcall)
9
+ lib.set_default_cc("AMD64", SimCCMicrosoftAMD64)
@@ -0,0 +1,12 @@
1
+ # pylint: disable=missing-class-docstring
2
+ import claripy
3
+
4
+ import angr
5
+
6
+
7
+ class ExAllocatePool(angr.SimProcedure):
8
+ def run(self, PoolType, NumberOfBytes): # pylint:disable=arguments-differ, unused-argument
9
+ addr = self.state.heap._malloc(NumberOfBytes)
10
+ memset = angr.SIM_PROCEDURES["libc"]["memset"]
11
+ self.inline_call(memset, addr, claripy.BVV(0, 8), NumberOfBytes) # zerofill
12
+ return addr
@@ -0,0 +1,7 @@
1
+ # pylint: disable=missing-class-docstring
2
+ from angr import SimProcedure
3
+
4
+
5
+ class ExFreePoolWithTag(SimProcedure):
6
+ def run(self, P, Tag): # pylint:disable=arguments-differ, unused-argument
7
+ self.state.heap._free(P)
@@ -0,0 +1,3 @@
1
+ """
2
+ These procedures implement functions from the Windows kernel.
3
+ """
@@ -58,7 +58,7 @@ class MemoryMixin(SimStatePlugin):
58
58
  to_add = c
59
59
  self.state.add_constraints(to_add)
60
60
 
61
- def load(self, addr, **kwargs):
61
+ def load(self, addr, size=None, **kwargs):
62
62
  pass
63
63
 
64
64
  def store(self, addr, data, **kwargs):
angr/utils/funcid.py ADDED
@@ -0,0 +1,128 @@
1
+ # pylint:disable=too-many-boolean-expressions
2
+ from typing import Optional
3
+
4
+ import capstone
5
+
6
+ from angr.knowledge_plugins.functions import Function
7
+
8
+
9
+ def is_function_security_check_cookie(func, project, security_cookie_addr: int) -> bool:
10
+ # disassemble the first instruction
11
+ if func.is_plt or func.is_syscall or func.is_simprocedure:
12
+ return False
13
+ block = project.factory.block(func.addr)
14
+ if block.instructions != 2:
15
+ return False
16
+ ins0 = block.capstone.insns[0]
17
+ if (
18
+ ins0.mnemonic == "cmp"
19
+ and len(ins0.operands) == 2
20
+ and ins0.operands[0].type == capstone.x86.X86_OP_REG
21
+ and ins0.operands[0].reg == capstone.x86.X86_REG_RCX
22
+ and ins0.operands[1].type == capstone.x86.X86_OP_MEM
23
+ and ins0.operands[1].mem.base == capstone.x86.X86_REG_RIP
24
+ and ins0.operands[1].mem.index == 0
25
+ and ins0.operands[1].mem.disp + ins0.address + ins0.size == security_cookie_addr
26
+ ):
27
+ ins1 = block.capstone.insns[1]
28
+ if ins1.mnemonic == "jne":
29
+ return True
30
+ return False
31
+
32
+
33
+ def is_function_security_init_cookie(func: "Function", project, security_cookie_addr: Optional[int]) -> bool:
34
+ if func.is_plt or func.is_syscall or func.is_simprocedure:
35
+ return False
36
+ # the function should have only one return point
37
+ if len(func.endpoints) == 1 and len(func.ret_sites) == 1:
38
+ # the function is normalized
39
+ ret_block = next(iter(func.ret_sites))
40
+ preds = [(pred.addr, pred.size) for pred in func.graph.predecessors(ret_block)]
41
+ if len(preds) != 2:
42
+ return False
43
+ elif len(func.endpoints) == 2 and len(func.ret_sites) == 2:
44
+ # the function is not normalized
45
+ ep0, ep1 = func.endpoints
46
+ if ep0.addr > ep1.addr:
47
+ ep0, ep1 = ep1, ep0
48
+ if ep0.addr + ep0.size == ep1.addr + ep1.size and ep0.addr < ep1.addr:
49
+ # overlapping block
50
+ preds = [(ep0.addr, ep1.addr - ep0.addr)]
51
+ else:
52
+ return False
53
+ else:
54
+ return False
55
+ for node_addr, node_size in preds:
56
+ # lift the block and check the last instruction
57
+ block = project.factory.block(node_addr, size=node_size)
58
+ if not block.instructions:
59
+ continue
60
+ last_insn = block.capstone.insns[-1]
61
+ if (
62
+ last_insn.mnemonic == "mov"
63
+ and len(last_insn.operands) == 2
64
+ and last_insn.operands[0].type == capstone.x86.X86_OP_MEM
65
+ and last_insn.operands[0].mem.base == capstone.x86.X86_REG_RIP
66
+ and last_insn.operands[0].mem.index == 0
67
+ and last_insn.operands[0].mem.disp + last_insn.address + last_insn.size == security_cookie_addr
68
+ and last_insn.operands[1].type == capstone.x86.X86_OP_REG
69
+ ):
70
+ return True
71
+ return False
72
+
73
+
74
+ def is_function_security_init_cookie_win8(func: "Function", project, security_cookie_addr: int) -> bool:
75
+ # disassemble the first instruction
76
+ if func.is_plt or func.is_syscall or func.is_simprocedure:
77
+ return False
78
+ block = project.factory.block(func.addr)
79
+ if block.instructions != 3:
80
+ return False
81
+ ins0 = block.capstone.insns[0]
82
+ if (
83
+ ins0.mnemonic == "mov"
84
+ and len(ins0.operands) == 2
85
+ and ins0.operands[0].type == capstone.x86.X86_OP_REG
86
+ and ins0.operands[0].reg == capstone.x86.X86_REG_RAX
87
+ and ins0.operands[1].type == capstone.x86.X86_OP_MEM
88
+ and ins0.operands[1].mem.base == capstone.x86.X86_REG_RIP
89
+ and ins0.operands[1].mem.index == 0
90
+ and ins0.operands[1].mem.disp + ins0.address + ins0.size == security_cookie_addr
91
+ ):
92
+ ins1 = block.capstone.insns[-1]
93
+ if ins1.mnemonic == "je":
94
+ succs = list(func.graph.successors(func.get_node(block.addr)))
95
+ if len(succs) > 2:
96
+ return False
97
+ for succ in succs:
98
+ succ_block = project.factory.block(succ.addr)
99
+ if succ_block.instructions:
100
+ first_insn = succ_block.capstone.insns[0]
101
+ if (
102
+ first_insn.mnemonic == "movabs"
103
+ and len(first_insn.operands) == 2
104
+ and first_insn.operands[1].type == capstone.x86.X86_OP_IMM
105
+ and first_insn.operands[1].imm == 0x2B992DDFA232
106
+ ):
107
+ return True
108
+ return False
109
+
110
+
111
+ def is_function_likely_security_init_cookie(func: "Function") -> bool:
112
+ """
113
+ Conducts a fuzzy match for security_init_cookie function.
114
+ """
115
+
116
+ callees = [node for node in func.transition_graph if isinstance(node, Function)]
117
+ callee_names = {callee.name for callee in callees}
118
+ if callee_names.issuperset(
119
+ {
120
+ "GetSystemTimeAsFileTime",
121
+ "GetCurrentProcessId",
122
+ "GetCurrentThreadId",
123
+ "GetTickCount",
124
+ "QueryPerformanceCounter",
125
+ }
126
+ ):
127
+ return True
128
+ return False