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.
- angr/__init__.py +1 -1
- angr/__main__.py +30 -5
- angr/analyses/cfg/cfg_fast.py +128 -3
- angr/analyses/decompiler/ail_simplifier.py +8 -0
- angr/analyses/decompiler/clinic.py +6 -2
- angr/analyses/decompiler/decompilation_options.py +9 -0
- angr/analyses/decompiler/optimization_passes/__init__.py +4 -0
- angr/analyses/decompiler/optimization_passes/multi_simplifier.py +0 -12
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +8 -5
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +2 -25
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +14 -2
- angr/analyses/decompiler/region_simplifiers/ifelse.py +19 -10
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +4 -2
- angr/analyses/decompiler/utils.py +8 -5
- angr/analyses/propagator/engine_ail.py +3 -1
- angr/analyses/propagator/engine_vex.py +45 -0
- angr/analyses/propagator/propagator.py +24 -15
- angr/analyses/reaching_definitions/engine_ail.py +1 -1
- angr/analyses/stack_pointer_tracker.py +55 -0
- angr/callable.py +4 -4
- angr/engines/light/engine.py +30 -18
- angr/knowledge_plugins/propagations/propagation_model.py +4 -0
- angr/knowledge_plugins/propagations/states.py +54 -4
- angr/lib/angr_native.dll +0 -0
- angr/procedures/definitions/__init__.py +2 -1
- angr/procedures/definitions/ntoskrnl.py +9 -0
- angr/procedures/win32_kernel/ExAllocatePool.py +12 -0
- angr/procedures/win32_kernel/ExFreePoolWithTag.py +7 -0
- angr/procedures/win32_kernel/__init__.py +3 -0
- angr/storage/memory_mixins/__init__.py +1 -1
- angr/utils/funcid.py +128 -0
- {angr-9.2.79.dist-info → angr-9.2.80.dist-info}/METADATA +6 -6
- {angr-9.2.79.dist-info → angr-9.2.80.dist-info}/RECORD +40 -35
- tests/analyses/cfg/test_cfgfast.py +24 -0
- tests/analyses/decompiler/test_decompiler.py +128 -0
- tests/analyses/test_constantpropagation.py +34 -0
- {angr-9.2.79.dist-info → angr-9.2.80.dist-info}/LICENSE +0 -0
- {angr-9.2.79.dist-info → angr-9.2.80.dist-info}/WHEEL +0 -0
- {angr-9.2.79.dist-info → angr-9.2.80.dist-info}/entry_points.txt +0 -0
- {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
|
-
|
|
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
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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)
|
angr/engines/light/engine.py
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
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
|