angr 9.2.76__py3-none-win_amd64.whl → 9.2.77__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/analyses/cfg/indirect_jump_resolvers/amd64_pe_iat.py +7 -1
- angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +7 -1
- angr/analyses/decompiler/clinic.py +4 -1
- angr/analyses/decompiler/condition_processor.py +4 -0
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +4 -3
- angr/analyses/decompiler/optimization_passes/multi_simplifier.py +1 -1
- angr/analyses/decompiler/structured_codegen/c.py +3 -0
- angr/analyses/propagator/engine_ail.py +1 -1
- angr/analyses/reaching_definitions/engine_ail.py +3 -6
- angr/analyses/reaching_definitions/engine_vex.py +32 -2
- angr/analyses/reaching_definitions/function_handler.py +1 -1
- angr/analyses/reaching_definitions/rd_initializer.py +6 -6
- angr/analyses/reaching_definitions/rd_state.py +9 -11
- angr/analyses/typehoon/typevars.py +19 -29
- angr/analyses/variable_recovery/variable_recovery_fast.py +33 -31
- angr/engines/light/engine.py +1 -1
- angr/keyed_region.py +19 -3
- angr/knowledge_plugins/functions/function.py +8 -0
- angr/knowledge_plugins/key_definitions/live_definitions.py +53 -44
- angr/knowledge_plugins/key_definitions/liveness.py +102 -34
- angr/knowledge_plugins/key_definitions/rd_model.py +4 -4
- angr/knowledge_plugins/propagations/states.py +3 -1
- angr/knowledge_plugins/variables/variable_manager.py +51 -25
- angr/lib/angr_native.dll +0 -0
- angr/misc/bug_report.py +2 -2
- angr/storage/memory_mixins/__init__.py +3 -2
- angr/storage/memory_mixins/paged_memory/paged_memory_multivalue_mixin.py +63 -0
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +5 -0
- {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/METADATA +6 -6
- {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/RECORD +37 -36
- tests/analyses/decompiler/test_decompiler.py +5 -1
- tests/analyses/test_flirt.py +3 -1
- tests/procedures/libc/test_string.py +2 -1
- {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/LICENSE +0 -0
- {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/WHEEL +0 -0
- {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
|
@@ -22,7 +22,13 @@ class AMD64PeIatResolver(IndirectJumpResolver):
|
|
|
22
22
|
if jumpkind not in {"Ijk_Call", "Ijk_Boring"}:
|
|
23
23
|
return False
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
insns = self.project.factory.block(addr).capstone.insns
|
|
26
|
+
if not insns:
|
|
27
|
+
return False
|
|
28
|
+
if not insns[-1].insn.operands:
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
opnd = insns[-1].insn.operands[0]
|
|
26
32
|
# Must be of the form: call qword ptr [0xABCD]
|
|
27
33
|
if opnd.type == X86_OP_MEM and opnd.mem.disp and opnd.mem.base == X86_REG_RIP and opnd.mem.index == 0:
|
|
28
34
|
return True
|
|
@@ -22,7 +22,13 @@ class X86PeIatResolver(IndirectJumpResolver):
|
|
|
22
22
|
if jumpkind != "Ijk_Call":
|
|
23
23
|
return False
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
insns = self.project.factory.block(addr).capstone.insns
|
|
26
|
+
if not insns:
|
|
27
|
+
return False
|
|
28
|
+
if not insns[-1].insn.operands:
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
opnd = insns[-1].insn.operands[0]
|
|
26
32
|
# Must be of the form: call ds:0xABCD
|
|
27
33
|
if opnd.type == X86_OP_MEM and opnd.mem.disp and not opnd.mem.base and not opnd.mem.index:
|
|
28
34
|
return True
|
|
@@ -1399,7 +1399,10 @@ class Clinic(Analysis):
|
|
|
1399
1399
|
)
|
|
1400
1400
|
end_block_ail = ailment.IRSBConverter.convert(end_block.vex, self._ail_manager)
|
|
1401
1401
|
else:
|
|
1402
|
-
|
|
1402
|
+
try:
|
|
1403
|
+
end_block_ail = next(iter(b for b in ail_graph if b.addr == end_block_addr))
|
|
1404
|
+
except StopIteration:
|
|
1405
|
+
return None
|
|
1403
1406
|
|
|
1404
1407
|
# last check: if the first instruction of the end block has Sar, then we bail (due to the peephole optimization
|
|
1405
1408
|
# SarToSignedDiv)
|
|
@@ -102,6 +102,7 @@ _ail2claripy_op_mapping = {
|
|
|
102
102
|
"Shr": lambda expr, conv, _: _op_with_unified_size(claripy.LShR, conv, expr.operands[0], expr.operands[1]),
|
|
103
103
|
"Shl": lambda expr, conv, _: _op_with_unified_size(operator.lshift, conv, expr.operands[0], expr.operands[1]),
|
|
104
104
|
"Sar": lambda expr, conv, _: _op_with_unified_size(operator.rshift, conv, expr.operands[0], expr.operands[1]),
|
|
105
|
+
"Concat": lambda expr, conv, _: claripy.Concat(*[conv(operand) for operand in expr.operands]),
|
|
105
106
|
# There are no corresponding claripy operations for the following operations
|
|
106
107
|
"DivMod": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
107
108
|
"CmpF": lambda expr, _, m: _dummy_bvs(expr, m),
|
|
@@ -686,6 +687,9 @@ class ConditionProcessor:
|
|
|
686
687
|
if cond_.args[0] is True
|
|
687
688
|
else ailment.Expr.Const(None, None, False, 1, **tags),
|
|
688
689
|
"Extract": lambda cond_, tags: self._convert_extract(*cond_.args, tags, memo=memo),
|
|
690
|
+
"ZeroExt": lambda cond_, tags: _binary_op_reduce(
|
|
691
|
+
"Concat", [claripy.BVV(0, cond_.args[0]), cond_.args[1]], tags
|
|
692
|
+
),
|
|
689
693
|
}
|
|
690
694
|
|
|
691
695
|
if cond.op in _mapping:
|
|
@@ -146,14 +146,15 @@ class ITERegionConverter(OptimizationPass):
|
|
|
146
146
|
#
|
|
147
147
|
|
|
148
148
|
new_region_head = region_head.copy()
|
|
149
|
+
addr_obj = true_stmt.src if "ins_addr" in true_stmt.src.tags else true_stmt
|
|
149
150
|
ternary_expr = ITE(
|
|
150
151
|
None,
|
|
151
152
|
region_head.statements[-1].condition,
|
|
152
153
|
true_stmt.src,
|
|
153
154
|
false_stmt.src,
|
|
154
|
-
ins_addr=
|
|
155
|
-
vex_block_addr=
|
|
156
|
-
vex_stmt_idx=
|
|
155
|
+
ins_addr=addr_obj.ins_addr,
|
|
156
|
+
vex_block_addr=addr_obj.vex_block_addr,
|
|
157
|
+
vex_stmt_idx=addr_obj.vex_stmt_idx,
|
|
157
158
|
)
|
|
158
159
|
new_assignment = true_stmt.copy()
|
|
159
160
|
new_assignment.src = ternary_expr
|
|
@@ -21,7 +21,7 @@ class MultiSimplifierAILEngine(SimplifierAILEngine):
|
|
|
21
21
|
if type(operand_0) in [Expr.Convert, Expr.Register]:
|
|
22
22
|
if isinstance(operand_1, (Expr.Convert, Expr.Register)):
|
|
23
23
|
if operand_0 == operand_1:
|
|
24
|
-
count = Expr.Const(expr.idx, None, 2,
|
|
24
|
+
count = Expr.Const(expr.idx, None, 2, operand_1.bits)
|
|
25
25
|
return Expr.BinaryOp(expr.idx, "Mul", [operand_1, count], expr.signed, **expr.tags)
|
|
26
26
|
# 2*x + x = 3*x
|
|
27
27
|
if Expr.BinaryOp in [type(operand_0), type(operand_1)]:
|
|
@@ -2721,6 +2721,9 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
2721
2721
|
o_constant, o_terms = extract_terms(expr)
|
|
2722
2722
|
|
|
2723
2723
|
def bail_out():
|
|
2724
|
+
if len(o_terms) == 0:
|
|
2725
|
+
# probably a plain integer, return as is
|
|
2726
|
+
return expr
|
|
2724
2727
|
result = reduce(
|
|
2725
2728
|
lambda a1, a2: CBinaryOp("Add", a1, a2, codegen=self),
|
|
2726
2729
|
(
|
|
@@ -1204,7 +1204,7 @@ class SimEnginePropagatorAIL(
|
|
|
1204
1204
|
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1205
1205
|
],
|
|
1206
1206
|
expr.signed,
|
|
1207
|
-
bits=
|
|
1207
|
+
bits=expr.bits,
|
|
1208
1208
|
floating_point=expr.floating_point,
|
|
1209
1209
|
rounding_mode=expr.rounding_mode,
|
|
1210
1210
|
**expr.tags,
|
|
@@ -118,9 +118,6 @@ class SimEngineRDAIL(
|
|
|
118
118
|
def _process_Stmt(self, whitelist=None):
|
|
119
119
|
super()._process_Stmt(whitelist=whitelist)
|
|
120
120
|
|
|
121
|
-
if self.state.analysis:
|
|
122
|
-
self.state.analysis.model.complete_loc()
|
|
123
|
-
|
|
124
121
|
def _handle_Stmt(self, stmt):
|
|
125
122
|
if self.state.analysis:
|
|
126
123
|
self.state.analysis.stmt_observe(self.stmt_idx, stmt, self.block, self.state, OP_BEFORE)
|
|
@@ -801,7 +798,7 @@ class SimEngineRDAIL(
|
|
|
801
798
|
elif expr0_v is None and expr1_v is not None:
|
|
802
799
|
# each value in expr0 >> expr1_v
|
|
803
800
|
if expr0.count() == 1 and 0 in expr0:
|
|
804
|
-
if all(v.concrete for v in expr0[0]):
|
|
801
|
+
if all(v.concrete for v in expr0[0]) and expr1_v.concrete:
|
|
805
802
|
vs = {
|
|
806
803
|
(claripy.LShR(v, expr1_v.concrete_value) if v.concrete else self.state.top(bits))
|
|
807
804
|
for v in expr0[0]
|
|
@@ -839,7 +836,7 @@ class SimEngineRDAIL(
|
|
|
839
836
|
elif expr0_v is None and expr1_v is not None:
|
|
840
837
|
# each value in expr0 >> expr1_v
|
|
841
838
|
if expr0.count() == 1 and 0 in expr0:
|
|
842
|
-
if all(v.concrete for v in expr0[0]):
|
|
839
|
+
if all(v.concrete for v in expr0[0]) and expr1_v.concrete:
|
|
843
840
|
vs = {
|
|
844
841
|
(claripy.LShR(v, expr1_v.concrete_value) if v.concrete else self.state.top(bits))
|
|
845
842
|
for v in expr0[0]
|
|
@@ -877,7 +874,7 @@ class SimEngineRDAIL(
|
|
|
877
874
|
elif expr0_v is None and expr1_v is not None:
|
|
878
875
|
# each value in expr0 << expr1_v
|
|
879
876
|
if expr0.count() == 1 and 0 in expr0:
|
|
880
|
-
if all(v.concrete for v in expr0[0]):
|
|
877
|
+
if all(v.concrete for v in expr0[0]) and expr1_v.concrete:
|
|
881
878
|
vs = {((v << expr1_v.concrete_value) if v.concrete else self.state.top(bits)) for v in expr0[0]}
|
|
882
879
|
r = MultiValues(offset_to_values={0: vs})
|
|
883
880
|
elif expr0_v is not None and expr1_v is None:
|
|
@@ -147,11 +147,11 @@ class SimEngineRDVEX(
|
|
|
147
147
|
if self.state.is_heap_address(d):
|
|
148
148
|
heap_offset = self.state.get_heap_offset(d)
|
|
149
149
|
if heap_offset is not None:
|
|
150
|
-
self.state.add_heap_use(heap_offset, 1
|
|
150
|
+
self.state.add_heap_use(heap_offset, 1)
|
|
151
151
|
elif self.state.is_stack_address(d):
|
|
152
152
|
stack_offset = self.state.get_stack_offset(d)
|
|
153
153
|
if stack_offset is not None:
|
|
154
|
-
self.state.add_stack_use(stack_offset, 1
|
|
154
|
+
self.state.add_stack_use(stack_offset, 1)
|
|
155
155
|
|
|
156
156
|
if self.state.exit_observed and reg_offset == self.arch.sp_offset:
|
|
157
157
|
return
|
|
@@ -989,6 +989,34 @@ class SimEngineRDVEX(
|
|
|
989
989
|
return MultiValues(claripy.BVV(0, 1))
|
|
990
990
|
return MultiValues(self.state.top(1))
|
|
991
991
|
|
|
992
|
+
def _handle_CmpGT(self, expr):
|
|
993
|
+
arg0, arg1 = expr.args
|
|
994
|
+
expr_0 = self._expr(arg0)
|
|
995
|
+
expr_1 = self._expr(arg1)
|
|
996
|
+
|
|
997
|
+
e0 = expr_0.one_value()
|
|
998
|
+
e1 = expr_1.one_value()
|
|
999
|
+
if e0 is not None and e1 is not None:
|
|
1000
|
+
if not e0.symbolic and not e1.symbolic:
|
|
1001
|
+
return MultiValues(claripy.BVV(1, 1) if e0.concrete_value > e1.concrete_value else claripy.BVV(0, 1))
|
|
1002
|
+
elif e0 is e1:
|
|
1003
|
+
return MultiValues(claripy.BVV(0, 1))
|
|
1004
|
+
return MultiValues(self.state.top(1))
|
|
1005
|
+
|
|
1006
|
+
def _handle_CmpGE(self, expr):
|
|
1007
|
+
arg0, arg1 = expr.args
|
|
1008
|
+
expr_0 = self._expr(arg0)
|
|
1009
|
+
expr_1 = self._expr(arg1)
|
|
1010
|
+
|
|
1011
|
+
e0 = expr_0.one_value()
|
|
1012
|
+
e1 = expr_1.one_value()
|
|
1013
|
+
if e0 is not None and e1 is not None:
|
|
1014
|
+
if not e0.symbolic and not e1.symbolic:
|
|
1015
|
+
return MultiValues(claripy.BVV(1, 1) if e0.concrete_value >= e1.concrete_value else claripy.BVV(0, 1))
|
|
1016
|
+
elif e0 is e1:
|
|
1017
|
+
return MultiValues(claripy.BVV(0, 1))
|
|
1018
|
+
return MultiValues(self.state.top(1))
|
|
1019
|
+
|
|
992
1020
|
# ppc only
|
|
993
1021
|
def _handle_CmpORD(self, expr):
|
|
994
1022
|
arg0, arg1 = expr.args
|
|
@@ -1001,6 +1029,8 @@ class SimEngineRDVEX(
|
|
|
1001
1029
|
|
|
1002
1030
|
if e0 is not None and e1 is not None:
|
|
1003
1031
|
if not e0.symbolic and not e1.symbolic:
|
|
1032
|
+
e0 = e0.concrete_value
|
|
1033
|
+
e1 = e1.concrete_value
|
|
1004
1034
|
if e0 < e1:
|
|
1005
1035
|
return MultiValues(claripy.BVV(0x8, bits))
|
|
1006
1036
|
elif e0 > e1:
|
|
@@ -409,7 +409,7 @@ class FunctionHandler:
|
|
|
409
409
|
# translate all the dep atoms into dep defns
|
|
410
410
|
for effect in data.effects:
|
|
411
411
|
if effect.sources_defns is None and effect.sources:
|
|
412
|
-
effect.sources_defns = set().union(*(
|
|
412
|
+
effect.sources_defns = set().union(*(state.get_definitions(atom) for atom in effect.sources))
|
|
413
413
|
if not effect.sources_defns:
|
|
414
414
|
effect.sources_defns = {Definition(atom, ExternalCodeLocation()) for atom in effect.sources}
|
|
415
415
|
other_input_defns |= effect.sources_defns - all_args_defns
|
|
@@ -63,7 +63,7 @@ class RDAStateInitializer:
|
|
|
63
63
|
self.initialize_architectural_state(state, func_addr, ex_loc, rtoc_value)
|
|
64
64
|
|
|
65
65
|
if state.analysis is not None:
|
|
66
|
-
state.analysis.model.
|
|
66
|
+
state.analysis.model.make_liveness_snapshot()
|
|
67
67
|
|
|
68
68
|
def initialize_all_function_arguments(
|
|
69
69
|
self,
|
|
@@ -147,7 +147,7 @@ class RDAStateInitializer:
|
|
|
147
147
|
rtoc_def = Definition(rtoc_atom, ex_loc, tags={InitialValueTag()})
|
|
148
148
|
state.all_definitions.add(rtoc_def)
|
|
149
149
|
if state.analysis is not None:
|
|
150
|
-
state.analysis.model.add_def(rtoc_def
|
|
150
|
+
state.analysis.model.add_def(rtoc_def)
|
|
151
151
|
rtoc = state.annotate_with_def(claripy.BVV(rtoc_value, self.arch.bits), rtoc_def)
|
|
152
152
|
state.registers.store(offset, rtoc)
|
|
153
153
|
elif self.arch.name.startswith("MIPS64"):
|
|
@@ -156,7 +156,7 @@ class RDAStateInitializer:
|
|
|
156
156
|
t9_def = Definition(t9_atom, ex_loc, tags={InitialValueTag()})
|
|
157
157
|
state.all_definitions.add(t9_def)
|
|
158
158
|
if state.analysis is not None:
|
|
159
|
-
state.analysis.model.add_def(t9_def
|
|
159
|
+
state.analysis.model.add_def(t9_def)
|
|
160
160
|
t9 = state.annotate_with_def(claripy.BVV(func_addr, self.arch.bits), t9_def)
|
|
161
161
|
state.registers.store(offset, t9)
|
|
162
162
|
elif self.arch.name.startswith("MIPS"):
|
|
@@ -167,7 +167,7 @@ class RDAStateInitializer:
|
|
|
167
167
|
t9_def = Definition(t9_atom, ex_loc, tags={InitialValueTag()})
|
|
168
168
|
state.all_definitions.add(t9_def)
|
|
169
169
|
if state.analysis is not None:
|
|
170
|
-
state.analysis.model.add_def(t9_def
|
|
170
|
+
state.analysis.model.add_def(t9_def)
|
|
171
171
|
t9 = state.annotate_with_def(claripy.BVV(func_addr, self.arch.bits), t9_def)
|
|
172
172
|
state.registers.store(t9_offset, t9)
|
|
173
173
|
|
|
@@ -185,7 +185,7 @@ class RDAStateInitializer:
|
|
|
185
185
|
reg_def = Definition(reg_atom, ex_loc, tags={ParameterTag(function=func_addr)})
|
|
186
186
|
state.all_definitions.add(reg_def)
|
|
187
187
|
if state.analysis is not None:
|
|
188
|
-
state.analysis.model.add_def(reg_def
|
|
188
|
+
state.analysis.model.add_def(reg_def)
|
|
189
189
|
if value is None:
|
|
190
190
|
value = state.top(self.arch.bits)
|
|
191
191
|
reg = state.annotate_with_def(value, reg_def)
|
|
@@ -198,7 +198,7 @@ class RDAStateInitializer:
|
|
|
198
198
|
ml_def = Definition(ml_atom, ex_loc, tags={ParameterTag(function=func_addr)})
|
|
199
199
|
state.all_definitions.add(ml_def)
|
|
200
200
|
if state.analysis is not None:
|
|
201
|
-
state.analysis.model.add_def(ml_def
|
|
201
|
+
state.analysis.model.add_def(ml_def)
|
|
202
202
|
ml = state.annotate_with_def(state.top(self.arch.bits), ml_def)
|
|
203
203
|
stack_address = state.get_stack_address(state.stack_address(arg.stack_offset))
|
|
204
204
|
state.stack.store(stack_address, ml, endness=self.arch.memory_endness)
|
|
@@ -328,7 +328,7 @@ class ReachingDefinitionsState:
|
|
|
328
328
|
Overwrite existing definitions w.r.t 'atom' with a dummy definition instance. A dummy definition will not be
|
|
329
329
|
removed during simplification.
|
|
330
330
|
"""
|
|
331
|
-
existing_defs =
|
|
331
|
+
existing_defs = self.live_definitions.get_definitions(atom)
|
|
332
332
|
|
|
333
333
|
self.live_definitions.kill_definitions(atom)
|
|
334
334
|
|
|
@@ -347,7 +347,7 @@ class ReachingDefinitionsState:
|
|
|
347
347
|
override_codeloc: Optional[CodeLocation] = None,
|
|
348
348
|
) -> Tuple[Optional[MultiValues], Set[Definition]]:
|
|
349
349
|
codeloc = override_codeloc or self.codeloc
|
|
350
|
-
existing_defs =
|
|
350
|
+
existing_defs = self.live_definitions.get_definitions(atom)
|
|
351
351
|
mv = self.live_definitions.kill_and_add_definition(
|
|
352
352
|
atom, codeloc, data, dummy=dummy, tags=tags, endness=endness, annotated=annotated
|
|
353
353
|
)
|
|
@@ -417,7 +417,7 @@ class ReachingDefinitionsState:
|
|
|
417
417
|
for def_ in existing_defs:
|
|
418
418
|
self.analysis.model.kill_def(def_)
|
|
419
419
|
for def_ in defs:
|
|
420
|
-
self.analysis.model.add_def(def_
|
|
420
|
+
self.analysis.model.add_def(def_)
|
|
421
421
|
|
|
422
422
|
return mv, defs
|
|
423
423
|
|
|
@@ -450,8 +450,8 @@ class ReachingDefinitionsState:
|
|
|
450
450
|
self.codeloc_uses.add(definition)
|
|
451
451
|
self.live_definitions.add_register_use_by_def(definition, self.codeloc, expr=expr)
|
|
452
452
|
|
|
453
|
-
def add_stack_use(self, stack_offset: int, size: int,
|
|
454
|
-
defs = self.live_definitions.get_stack_definitions(stack_offset, size
|
|
453
|
+
def add_stack_use(self, stack_offset: int, size: int, expr: Optional[Any] = None) -> None:
|
|
454
|
+
defs = self.live_definitions.get_stack_definitions(stack_offset, size)
|
|
455
455
|
self.add_stack_use_by_defs(defs, expr=expr)
|
|
456
456
|
|
|
457
457
|
def add_stack_use_by_defs(self, defs: Iterable[Definition], expr: Optional[Any] = None):
|
|
@@ -459,8 +459,8 @@ class ReachingDefinitionsState:
|
|
|
459
459
|
self.codeloc_uses.add(definition)
|
|
460
460
|
self.live_definitions.add_stack_use_by_def(definition, self.codeloc, expr=expr)
|
|
461
461
|
|
|
462
|
-
def add_heap_use(self, heap_offset: int, size: int,
|
|
463
|
-
defs = self.live_definitions.get_heap_definitions(heap_offset, size
|
|
462
|
+
def add_heap_use(self, heap_offset: int, size: int, expr: Optional[Any] = None) -> None:
|
|
463
|
+
defs = self.live_definitions.get_heap_definitions(heap_offset, size)
|
|
464
464
|
self.add_heap_use_by_defs(defs, expr=expr)
|
|
465
465
|
|
|
466
466
|
def add_heap_use_by_defs(self, defs: Iterable[Definition], expr: Optional[Any] = None):
|
|
@@ -477,10 +477,8 @@ class ReachingDefinitionsState:
|
|
|
477
477
|
self.codeloc_uses.add(definition)
|
|
478
478
|
self.live_definitions.add_memory_use_by_def(definition, self.codeloc, expr=expr)
|
|
479
479
|
|
|
480
|
-
def get_definitions(
|
|
481
|
-
self
|
|
482
|
-
) -> Iterable[Definition]:
|
|
483
|
-
yield from self.live_definitions.get_definitions(atom)
|
|
480
|
+
def get_definitions(self, atom: Union[Atom, Definition, Iterable[Atom], Iterable[Definition]]) -> Set[Definition]:
|
|
481
|
+
return self.live_definitions.get_definitions(atom)
|
|
484
482
|
|
|
485
483
|
def get_values(self, spec: Union[Atom, Definition, Iterable[Atom]]) -> Optional[MultiValues]:
|
|
486
484
|
return self.live_definitions.get_values(spec)
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# pylint:disable=missing-class-docstring
|
|
2
|
-
from typing import Dict, Any, Optional, TYPE_CHECKING
|
|
2
|
+
from typing import Dict, Any, Optional, Set, TYPE_CHECKING
|
|
3
3
|
from itertools import count
|
|
4
4
|
|
|
5
|
-
from ...utils.cowdict import ChainMapCOW
|
|
6
|
-
|
|
7
5
|
if TYPE_CHECKING:
|
|
8
6
|
from angr.sim_variable import SimVariable
|
|
9
7
|
|
|
@@ -340,25 +338,20 @@ class DerivedTypeVariable(TypeVariable):
|
|
|
340
338
|
|
|
341
339
|
|
|
342
340
|
class TypeVariables:
|
|
343
|
-
__slots__ = (
|
|
341
|
+
__slots__ = (
|
|
342
|
+
"_typevars",
|
|
343
|
+
"_last_typevars",
|
|
344
|
+
)
|
|
344
345
|
|
|
345
346
|
def __init__(self):
|
|
346
|
-
self._typevars: Dict["SimVariable", TypeVariable] =
|
|
347
|
-
|
|
348
|
-
def merge(self, tvs):
|
|
349
|
-
merged = TypeVariables()
|
|
350
|
-
|
|
351
|
-
# TODO: Replace this with a real lattice-based merging
|
|
352
|
-
merged._typevars = self._typevars.copy()
|
|
353
|
-
if tvs._typevars:
|
|
354
|
-
merged._typevars = merged._typevars.clean()
|
|
355
|
-
merged._typevars.update(tvs._typevars)
|
|
356
|
-
|
|
357
|
-
return merged
|
|
347
|
+
self._typevars: Dict["SimVariable", Set[TypeVariable]] = {}
|
|
348
|
+
self._last_typevars: Dict[SimVariable, TypeVariable] = {}
|
|
358
349
|
|
|
359
350
|
def copy(self):
|
|
360
351
|
copied = TypeVariables()
|
|
361
|
-
|
|
352
|
+
for var, typevars in self._typevars.items():
|
|
353
|
+
copied._typevars[var] = typevars.copy()
|
|
354
|
+
copied._last_typevars = self._last_typevars.copy()
|
|
362
355
|
return copied
|
|
363
356
|
|
|
364
357
|
def __repr__(self):
|
|
@@ -369,27 +362,24 @@ class TypeVariables:
|
|
|
369
362
|
return "{TypeVars: %d items}" % len(self._typevars)
|
|
370
363
|
|
|
371
364
|
def add_type_variable(self, var: "SimVariable", codeloc, typevar: TypeVariable): # pylint:disable=unused-argument
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
self.
|
|
378
|
-
self._typevars[var] = typevar
|
|
365
|
+
if var not in self._typevars:
|
|
366
|
+
self._typevars[var] = set()
|
|
367
|
+
elif typevar in self._typevars[var]:
|
|
368
|
+
return
|
|
369
|
+
self._typevars[var].add(typevar)
|
|
370
|
+
self._last_typevars[var] = typevar
|
|
379
371
|
|
|
380
372
|
def get_type_variable(self, var, codeloc): # pylint:disable=unused-argument
|
|
381
|
-
return self.
|
|
373
|
+
return self._last_typevars[var]
|
|
382
374
|
|
|
383
375
|
def has_type_variable_for(self, var: "SimVariable", codeloc): # pylint:disable=unused-argument
|
|
384
|
-
|
|
385
|
-
return False
|
|
386
|
-
return True
|
|
376
|
+
return var in self._typevars
|
|
387
377
|
# if codeloc not in self._typevars[var]:
|
|
388
378
|
# return False
|
|
389
379
|
# return True
|
|
390
380
|
|
|
391
381
|
def __getitem__(self, var):
|
|
392
|
-
return self.
|
|
382
|
+
return self._last_typevars[var]
|
|
393
383
|
|
|
394
384
|
def __contains__(self, var):
|
|
395
385
|
return var in self._typevars
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# pylint:disable=wrong-import-position,wrong-import-order
|
|
2
|
-
from typing import Optional, List, Tuple, Union
|
|
2
|
+
from typing import Optional, List, Tuple, Union, DefaultDict, Set
|
|
3
3
|
import logging
|
|
4
4
|
from collections import defaultdict
|
|
5
5
|
|
|
@@ -17,7 +17,7 @@ from ...knowledge_plugins import Function
|
|
|
17
17
|
from ...sim_variable import SimStackVariable, SimRegisterVariable, SimVariable, SimMemoryVariable
|
|
18
18
|
from ...engines.vex.claripy.irop import vexop_to_simop
|
|
19
19
|
from angr.analyses import ForwardAnalysis, visitors
|
|
20
|
-
from ..typehoon.typevars import Equivalence, TypeVariable
|
|
20
|
+
from ..typehoon.typevars import Equivalence, TypeVariable, TypeVariables
|
|
21
21
|
from .variable_recovery_base import VariableRecoveryBase, VariableRecoveryStateBase
|
|
22
22
|
from .engine_vex import SimEngineVRVEX
|
|
23
23
|
from .engine_ail import SimEngineVRAIL
|
|
@@ -86,9 +86,9 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
|
|
|
86
86
|
stack_region=self.stack_region.copy(),
|
|
87
87
|
register_region=self.register_region.copy(),
|
|
88
88
|
global_region=self.global_region.copy(),
|
|
89
|
-
typevars=self.typevars
|
|
90
|
-
type_constraints=self.type_constraints
|
|
91
|
-
delayed_type_constraints=self.delayed_type_constraints
|
|
89
|
+
typevars=self.typevars,
|
|
90
|
+
type_constraints=self.type_constraints,
|
|
91
|
+
delayed_type_constraints=self.delayed_type_constraints,
|
|
92
92
|
stack_offset_typevars=dict(self.stack_offset_typevars),
|
|
93
93
|
project=self.project,
|
|
94
94
|
ret_val_size=self.ret_val_size,
|
|
@@ -125,26 +125,17 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
|
|
|
125
125
|
merged_global_region.set_state(self)
|
|
126
126
|
merge_occurred |= merged_global_region.merge([other.global_region for other in others], None)
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
delayed_typeconstraints = self.delayed_type_constraints
|
|
131
|
-
for other in others:
|
|
132
|
-
merged_typevars = merged_typevars.merge(other.typevars)
|
|
133
|
-
merged_typeconstraints |= other.type_constraints
|
|
134
|
-
for v, cons in other.delayed_type_constraints.items():
|
|
135
|
-
delayed_typeconstraints[v] |= cons
|
|
136
|
-
|
|
137
|
-
merge_occurred |= self.typevars != merged_typevars
|
|
138
|
-
merge_occurred |= self.type_constraints != merged_typeconstraints
|
|
139
|
-
merge_occurred |= self.delayed_type_constraints != delayed_typeconstraints
|
|
128
|
+
typevars = self.typevars
|
|
129
|
+
type_constraints = self.type_constraints
|
|
130
|
+
delayed_typeconstraints = self.delayed_type_constraints
|
|
140
131
|
|
|
141
132
|
# add subtype constraints for all replacements
|
|
142
133
|
for v0, v1 in self.phi_variables.items():
|
|
143
134
|
# v0 will be replaced by v1
|
|
144
|
-
if not
|
|
145
|
-
|
|
146
|
-
if not
|
|
147
|
-
|
|
135
|
+
if not typevars.has_type_variable_for(v1, None):
|
|
136
|
+
typevars.add_type_variable(v1, None, TypeVariable())
|
|
137
|
+
if not typevars.has_type_variable_for(v0, None):
|
|
138
|
+
typevars.add_type_variable(v0, None, TypeVariable())
|
|
148
139
|
# Assuming v2 = phi(v0, v1), then we know that v0_typevar == v1_typevar == v2_typevar
|
|
149
140
|
# However, it's possible that neither v0 nor v1 will ever be used in future blocks, which not only makes
|
|
150
141
|
# this phi function useless, but also leads to the incorrect assumption that v1_typevar == v2_typevar.
|
|
@@ -152,9 +143,7 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
|
|
|
152
143
|
# when v1 (the new variable that will end up in the state) is ever used in the future.
|
|
153
144
|
|
|
154
145
|
# create an equivalence relationship
|
|
155
|
-
equivalence = Equivalence(
|
|
156
|
-
merged_typevars.get_type_variable(v1, None), merged_typevars.get_type_variable(v0, None)
|
|
157
|
-
)
|
|
146
|
+
equivalence = Equivalence(typevars.get_type_variable(v1, None), typevars.get_type_variable(v0, None))
|
|
158
147
|
delayed_typeconstraints[v1].add(equivalence)
|
|
159
148
|
|
|
160
149
|
stack_offset_typevars = {}
|
|
@@ -173,7 +162,7 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
|
|
|
173
162
|
else:
|
|
174
163
|
typevar = TypeVariable()
|
|
175
164
|
for orig_typevar in all_typevars:
|
|
176
|
-
|
|
165
|
+
type_constraints.add(Equivalence(orig_typevar, typevar))
|
|
177
166
|
stack_offset_typevars[offset] = typevar
|
|
178
167
|
|
|
179
168
|
ret_val_size = self.ret_val_size
|
|
@@ -195,8 +184,8 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
|
|
|
195
184
|
stack_region=merged_stack_region,
|
|
196
185
|
register_region=merged_register_region,
|
|
197
186
|
global_region=merged_global_region,
|
|
198
|
-
typevars=
|
|
199
|
-
type_constraints=
|
|
187
|
+
typevars=typevars,
|
|
188
|
+
type_constraints=type_constraints,
|
|
200
189
|
delayed_type_constraints=delayed_typeconstraints,
|
|
201
190
|
stack_offset_typevars=stack_offset_typevars,
|
|
202
191
|
project=self.project,
|
|
@@ -205,6 +194,9 @@ class VariableRecoveryFastState(VariableRecoveryStateBase):
|
|
|
205
194
|
|
|
206
195
|
return state, merge_occurred
|
|
207
196
|
|
|
197
|
+
def downsize(self) -> None:
|
|
198
|
+
pass
|
|
199
|
+
|
|
208
200
|
#
|
|
209
201
|
# Util methods
|
|
210
202
|
#
|
|
@@ -277,8 +269,10 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
277
269
|
self._node_iterations = defaultdict(int)
|
|
278
270
|
|
|
279
271
|
self._node_to_cc = {}
|
|
280
|
-
self.var_to_typevars = defaultdict(set)
|
|
272
|
+
self.var_to_typevars: DefaultDict[SimVariable, Set[TypeVariable]] = defaultdict(set)
|
|
273
|
+
self.typevars = None
|
|
281
274
|
self.type_constraints = None
|
|
275
|
+
self.delayed_type_constraints = None
|
|
282
276
|
self.ret_val_size = None
|
|
283
277
|
|
|
284
278
|
self._analyze()
|
|
@@ -293,7 +287,9 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
293
287
|
#
|
|
294
288
|
|
|
295
289
|
def _pre_analysis(self):
|
|
290
|
+
self.typevars = TypeVariables()
|
|
296
291
|
self.type_constraints = set()
|
|
292
|
+
self.delayed_type_constraints = defaultdict(set)
|
|
297
293
|
|
|
298
294
|
self.initialize_dominance_frontiers()
|
|
299
295
|
|
|
@@ -321,6 +317,9 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
321
317
|
self.project.arch,
|
|
322
318
|
self.function,
|
|
323
319
|
project=self.project,
|
|
320
|
+
typevars=self.typevars,
|
|
321
|
+
type_constraints=self.type_constraints,
|
|
322
|
+
delayed_type_constraints=self.delayed_type_constraints,
|
|
324
323
|
)
|
|
325
324
|
initial_sp = state.stack_address(self.project.arch.bytes if self.project.arch.call_pushes_ret else 0)
|
|
326
325
|
if self.project.arch.sp_offset is not None:
|
|
@@ -434,9 +433,6 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
434
433
|
self._process_block(state, block)
|
|
435
434
|
|
|
436
435
|
self._node_iterations[block_key] += 1
|
|
437
|
-
self.type_constraints |= state.type_constraints
|
|
438
|
-
for var, typevar in state.typevars._typevars.items():
|
|
439
|
-
self.var_to_typevars[var].add(typevar)
|
|
440
436
|
|
|
441
437
|
if state.ret_val_size is not None:
|
|
442
438
|
if self.ret_val_size is None or self.ret_val_size < state.ret_val_size:
|
|
@@ -467,6 +463,10 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
467
463
|
if self._unify_variables:
|
|
468
464
|
self.variable_manager[self.function.addr].unify_variables()
|
|
469
465
|
|
|
466
|
+
# fill in var_to_typevars
|
|
467
|
+
for var, typevar_set in self.typevars._typevars.items():
|
|
468
|
+
self.var_to_typevars[var] = typevar_set
|
|
469
|
+
|
|
470
470
|
# unify type variables for global variables
|
|
471
471
|
for var, typevars in self.var_to_typevars.items():
|
|
472
472
|
if len(typevars) > 1 and isinstance(var, SimMemoryVariable) and not isinstance(var, SimStackVariable):
|
|
@@ -476,6 +476,8 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
476
476
|
|
|
477
477
|
self.variable_manager[self.function.addr].ret_val_size = self.ret_val_size
|
|
478
478
|
|
|
479
|
+
self.delayed_type_constraints = None
|
|
480
|
+
|
|
479
481
|
#
|
|
480
482
|
# Private methods
|
|
481
483
|
#
|
angr/engines/light/engine.py
CHANGED
|
@@ -547,7 +547,7 @@ class SimEngineLightVEXMixin(SimEngineLightMixin):
|
|
|
547
547
|
to_size = expr_1.size()
|
|
548
548
|
if signed:
|
|
549
549
|
quotient = expr_0.SDiv(claripy.SignExt(from_size - to_size, expr_1))
|
|
550
|
-
remainder =
|
|
550
|
+
remainder = expr_0.SMod(claripy.SignExt(from_size - to_size, expr_1))
|
|
551
551
|
quotient_size = to_size
|
|
552
552
|
remainder_size = to_size
|
|
553
553
|
return claripy.Concat(
|
angr/keyed_region.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import weakref
|
|
3
|
-
from typing import Union, TYPE_CHECKING
|
|
3
|
+
from typing import Union, Optional, Tuple, TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from sortedcontainers import SortedDict
|
|
6
6
|
|
|
@@ -133,7 +133,7 @@ class KeyedRegion:
|
|
|
133
133
|
self._storage, om, self._phi_node_contains = s
|
|
134
134
|
self._object_mapping = weakref.WeakValueDictionary(om)
|
|
135
135
|
|
|
136
|
-
def _get_container(self, offset):
|
|
136
|
+
def _get_container(self, offset) -> Tuple[int, Optional[RegionObject]]:
|
|
137
137
|
try:
|
|
138
138
|
base_offset = next(self._storage.irange(maximum=offset, reverse=True))
|
|
139
139
|
except StopIteration:
|
|
@@ -419,7 +419,23 @@ class KeyedRegion:
|
|
|
419
419
|
|
|
420
420
|
# is there a region item that begins before the start and overlaps with this variable?
|
|
421
421
|
floor_key, floor_item = self._get_container(start)
|
|
422
|
-
if floor_item is
|
|
422
|
+
if floor_item is None:
|
|
423
|
+
# fast path: just insert it
|
|
424
|
+
self._storage[start] = RegionObject(start, object_size, {stored_object})
|
|
425
|
+
return
|
|
426
|
+
|
|
427
|
+
# fast path: if there is a perfect overlap, just update the item
|
|
428
|
+
if len(overlapping_items) == 1 and floor_item.start == start and floor_item.end == end:
|
|
429
|
+
if overwrite:
|
|
430
|
+
floor_item.set_object(stored_object)
|
|
431
|
+
elif merge_to_top is False and top is None:
|
|
432
|
+
floor_item.add_object(stored_object)
|
|
433
|
+
else:
|
|
434
|
+
self._add_object_with_check(floor_item, stored_object, merge_to_top=merge_to_top, top=top)
|
|
435
|
+
return
|
|
436
|
+
|
|
437
|
+
# slower path: there are multiple overlapping items
|
|
438
|
+
if floor_key not in overlapping_items:
|
|
423
439
|
# insert it into the beginning
|
|
424
440
|
overlapping_items.insert(0, floor_key)
|
|
425
441
|
|
|
@@ -648,6 +648,14 @@ class Function(Serializable):
|
|
|
648
648
|
"""
|
|
649
649
|
return self.binary.loader.find_symbol(self.addr)
|
|
650
650
|
|
|
651
|
+
@property
|
|
652
|
+
def pseudocode(self) -> str:
|
|
653
|
+
"""
|
|
654
|
+
:return: the function's pseudocode
|
|
655
|
+
"""
|
|
656
|
+
dec = self.project.analyses.Decompiler(self, cfg=self._function_manager._kb.cfgs.get_most_accurate())
|
|
657
|
+
return dec.codegen.text
|
|
658
|
+
|
|
651
659
|
def add_jumpout_site(self, node):
|
|
652
660
|
"""
|
|
653
661
|
Add a custom jumpout site.
|