angr 9.2.61__py3-none-macosx_10_9_x86_64.whl → 9.2.63__py3-none-macosx_10_9_x86_64.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/cfg_fast.py +18 -20
- angr/analyses/decompiler/ail_simplifier.py +15 -30
- angr/analyses/decompiler/block_simplifier.py +11 -7
- angr/analyses/decompiler/clinic.py +144 -0
- angr/analyses/decompiler/condition_processor.py +4 -2
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +2 -0
- angr/analyses/decompiler/structured_codegen/c.py +20 -16
- angr/analyses/decompiler/structuring/phoenix.py +6 -10
- angr/analyses/disassembly.py +7 -11
- angr/analyses/propagator/engine_ail.py +14 -42
- angr/analyses/propagator/outdated_definition_walker.py +17 -53
- angr/analyses/propagator/propagator.py +1 -0
- angr/analyses/reaching_definitions/engine_ail.py +20 -9
- angr/analyses/reaching_definitions/engine_vex.py +20 -5
- angr/analyses/reaching_definitions/function_handler.py +9 -3
- angr/analyses/reaching_definitions/rd_state.py +34 -13
- angr/analyses/reaching_definitions/reaching_definitions.py +92 -16
- angr/analyses/variable_recovery/engine_vex.py +20 -0
- angr/analyses/variable_recovery/variable_recovery_fast.py +5 -0
- angr/calling_conventions.py +28 -0
- angr/knowledge_plugins/key_definitions/live_definitions.py +15 -5
- angr/knowledge_plugins/key_definitions/liveness.py +94 -0
- angr/knowledge_plugins/key_definitions/rd_model.py +90 -9
- angr/knowledge_plugins/propagations/states.py +3 -0
- angr/knowledge_plugins/variables/variable_manager.py +26 -4
- angr/lib/angr_native.dylib +0 -0
- angr/project.py +2 -2
- angr/sim_type.py +2 -2
- angr/state_plugins/unicorn_engine.py +9 -1
- angr/storage/memory_mixins/multi_value_merger_mixin.py +7 -2
- angr/utils/timing.py +12 -5
- {angr-9.2.61.dist-info → angr-9.2.63.dist-info}/METADATA +15 -15
- {angr-9.2.61.dist-info → angr-9.2.63.dist-info}/RECORD +37 -36
- {angr-9.2.61.dist-info → angr-9.2.63.dist-info}/WHEEL +1 -1
- {angr-9.2.61.dist-info → angr-9.2.63.dist-info}/LICENSE +0 -0
- {angr-9.2.61.dist-info → angr-9.2.63.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
angr/analyses/cfg/cfg_fast.py
CHANGED
|
@@ -2714,30 +2714,28 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
2714
2714
|
for segment in self.project.loader.main_object.segments:
|
|
2715
2715
|
if segment.vaddr + segment.memsize == data_addr:
|
|
2716
2716
|
# yeah!
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
self.kb.xrefs.add_xref(cr)
|
|
2717
|
+
self.model.add_memory_data(data_addr, MemoryDataSort.SegmentBoundary, data_size=0)
|
|
2718
|
+
cr = XRef(
|
|
2719
|
+
ins_addr=insn_addr,
|
|
2720
|
+
block_addr=irsb_addr,
|
|
2721
|
+
stmt_idx=stmt_idx,
|
|
2722
|
+
memory_data=self.model.memory_data[data_addr],
|
|
2723
|
+
xref_type=XRefType.Offset,
|
|
2724
|
+
)
|
|
2725
|
+
self.kb.xrefs.add_xref(cr)
|
|
2727
2726
|
break
|
|
2728
2727
|
|
|
2729
2728
|
return
|
|
2730
2729
|
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
self.kb.xrefs.add_xref(cr)
|
|
2730
|
+
self.model.add_memory_data(data_addr, data_type, data_size=data_size)
|
|
2731
|
+
cr = XRef(
|
|
2732
|
+
ins_addr=insn_addr,
|
|
2733
|
+
block_addr=irsb_addr,
|
|
2734
|
+
stmt_idx=stmt_idx,
|
|
2735
|
+
memory_data=self.model.memory_data[data_addr],
|
|
2736
|
+
xref_type=XRefType.Offset,
|
|
2737
|
+
)
|
|
2738
|
+
self.kb.xrefs.add_xref(cr)
|
|
2741
2739
|
|
|
2742
2740
|
if is_arm_arch(self.project.arch):
|
|
2743
2741
|
if (irsb_addr & 1) == 1 and data_addr == (insn_addr & 0xFFFF_FFFF_FFFF_FFFE) + 4:
|
|
@@ -18,7 +18,6 @@ from ailment.expression import (
|
|
|
18
18
|
BinaryOp,
|
|
19
19
|
)
|
|
20
20
|
|
|
21
|
-
from ...errors import SimMemoryMissingError
|
|
22
21
|
from ...engines.light import SpOffset
|
|
23
22
|
from ...code_location import CodeLocation
|
|
24
23
|
from ...analyses.reaching_definitions.external_codeloc import ExternalCodeLocation
|
|
@@ -35,7 +34,7 @@ from .ccall_rewriters import CCALL_REWRITERS
|
|
|
35
34
|
|
|
36
35
|
if TYPE_CHECKING:
|
|
37
36
|
from ailment.manager import Manager
|
|
38
|
-
from angr.analyses.reaching_definitions import
|
|
37
|
+
from angr.analyses.reaching_definitions import ReachingDefinitionsModel
|
|
39
38
|
|
|
40
39
|
|
|
41
40
|
_l = logging.getLogger(__name__)
|
|
@@ -103,7 +102,7 @@ class AILSimplifier(Analysis):
|
|
|
103
102
|
):
|
|
104
103
|
self.func = func
|
|
105
104
|
self.func_graph = func_graph if func_graph is not None else func.graph
|
|
106
|
-
self._reaching_definitions: Optional[
|
|
105
|
+
self._reaching_definitions: Optional["ReachingDefinitionsModel"] = None
|
|
107
106
|
self._propagator = None
|
|
108
107
|
|
|
109
108
|
self._remove_dead_memdefs = remove_dead_memdefs
|
|
@@ -191,7 +190,7 @@ class AILSimplifier(Analysis):
|
|
|
191
190
|
AILGraphWalker(self.func_graph, _handler, replace_nodes=True).walk()
|
|
192
191
|
self.blocks = {}
|
|
193
192
|
|
|
194
|
-
def _compute_reaching_definitions(self) -> "
|
|
193
|
+
def _compute_reaching_definitions(self) -> "ReachingDefinitionsModel":
|
|
195
194
|
# Computing reaching definitions or return the cached one
|
|
196
195
|
if self._reaching_definitions is not None:
|
|
197
196
|
return self._reaching_definitions
|
|
@@ -199,17 +198,12 @@ class AILSimplifier(Analysis):
|
|
|
199
198
|
subject=self.func,
|
|
200
199
|
func_graph=self.func_graph,
|
|
201
200
|
# init_context=(), <-- in case of fire break glass
|
|
202
|
-
observe_all=
|
|
201
|
+
observe_all=False,
|
|
203
202
|
use_callee_saved_regs_at_return=self._use_callee_saved_regs_at_return,
|
|
204
|
-
)
|
|
203
|
+
).model
|
|
205
204
|
self._reaching_definitions = rd
|
|
206
205
|
return rd
|
|
207
206
|
|
|
208
|
-
@staticmethod
|
|
209
|
-
# pylint:disable=unused-argument
|
|
210
|
-
def _simplify_function_rd_observe_callback(ob_type, **kwargs):
|
|
211
|
-
return ob_type == "node" or (ob_type == "insn" and kwargs.get("op_type", None) == OP_BEFORE)
|
|
212
|
-
|
|
213
207
|
def _compute_propagation(self):
|
|
214
208
|
# Propagate expressions or return the existing result
|
|
215
209
|
if self._propagator is not None:
|
|
@@ -772,7 +766,7 @@ class AILSimplifier(Analysis):
|
|
|
772
766
|
# ensure the expression that we want to replace with is still up-to-date
|
|
773
767
|
replace_with_original_def = self._find_atom_def_at(replace_with, rd, def_.codeloc)
|
|
774
768
|
if replace_with_original_def is not None and not self._check_atom_last_def(
|
|
775
|
-
replace_with,
|
|
769
|
+
replace_with, u, rd, replace_with_original_def
|
|
776
770
|
):
|
|
777
771
|
all_uses_replaced = False
|
|
778
772
|
continue
|
|
@@ -813,26 +807,18 @@ class AILSimplifier(Analysis):
|
|
|
813
807
|
@staticmethod
|
|
814
808
|
def _find_atom_def_at(atom, rd, codeloc: CodeLocation) -> Optional[Definition]:
|
|
815
809
|
if isinstance(atom, Register):
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
defs = list(observ.extract_defs_from_mv(reg_vals))
|
|
820
|
-
return defs[0] if len(defs) == 1 else None
|
|
821
|
-
except SimMemoryMissingError:
|
|
822
|
-
pass
|
|
810
|
+
defs = rd.get_defs(atom, codeloc, OP_BEFORE)
|
|
811
|
+
return next(iter(defs)) if len(defs) == 1 else None
|
|
812
|
+
|
|
823
813
|
return None
|
|
824
814
|
|
|
825
815
|
@staticmethod
|
|
826
|
-
def _check_atom_last_def(atom,
|
|
816
|
+
def _check_atom_last_def(atom, codeloc, rd, the_def) -> bool:
|
|
827
817
|
if isinstance(atom, Register):
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
if existing_def.codeloc != the_def.codeloc:
|
|
833
|
-
return False
|
|
834
|
-
except SimMemoryMissingError:
|
|
835
|
-
pass
|
|
818
|
+
defs = rd.get_defs(atom, codeloc, OP_BEFORE)
|
|
819
|
+
for d in defs:
|
|
820
|
+
if d.codeloc != the_def.codeloc:
|
|
821
|
+
return False
|
|
836
822
|
|
|
837
823
|
return True
|
|
838
824
|
|
|
@@ -961,10 +947,9 @@ class AILSimplifier(Analysis):
|
|
|
961
947
|
defsite_defs_per_atom = defaultdict(set)
|
|
962
948
|
for dd in defsite_all_expr_uses:
|
|
963
949
|
defsite_defs_per_atom[dd.atom].add(dd)
|
|
964
|
-
usesite_rdstate = rd.observed_results[("stmt", (u.block_addr, u.block_idx, u.stmt_idx), 0)]
|
|
965
950
|
usesite_expr_def_outdated = False
|
|
966
951
|
for defsite_expr_atom, defsite_expr_uses in defsite_defs_per_atom.items():
|
|
967
|
-
usesite_expr_uses = set(
|
|
952
|
+
usesite_expr_uses = set(rd.get_defs(defsite_expr_atom, u, OP_BEFORE))
|
|
968
953
|
if not usesite_expr_uses:
|
|
969
954
|
# the atom is not defined at the use site - it's fine
|
|
970
955
|
continue
|
|
@@ -123,15 +123,19 @@ class BlockSimplifier(Analysis):
|
|
|
123
123
|
|
|
124
124
|
def _compute_reaching_definitions(self, block):
|
|
125
125
|
def observe_callback(ob_type, addr=None, op_type=None, **kwargs) -> bool: # pylint:disable=unused-argument
|
|
126
|
-
return ob_type == "
|
|
126
|
+
return ob_type == "node" and addr == block.addr and op_type == OP_AFTER
|
|
127
127
|
|
|
128
128
|
if self._reaching_definitions is None:
|
|
129
|
-
self._reaching_definitions =
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
self._reaching_definitions = (
|
|
130
|
+
self.project.analyses[ReachingDefinitionsAnalysis]
|
|
131
|
+
.prep()(
|
|
132
|
+
subject=block,
|
|
133
|
+
track_tmps=True,
|
|
134
|
+
stack_pointer_tracker=self._stack_pointer_tracker,
|
|
135
|
+
observe_all=False,
|
|
136
|
+
observe_callback=observe_callback,
|
|
137
|
+
)
|
|
138
|
+
.model
|
|
135
139
|
)
|
|
136
140
|
return self._reaching_definitions
|
|
137
141
|
|
|
@@ -176,6 +176,7 @@ class Clinic(Analysis):
|
|
|
176
176
|
self._convert_all()
|
|
177
177
|
|
|
178
178
|
ail_graph = self._make_ailgraph()
|
|
179
|
+
self._rewrite_ite_expressions(ail_graph)
|
|
179
180
|
self._remove_redundant_jump_blocks(ail_graph)
|
|
180
181
|
if self._insert_labels:
|
|
181
182
|
self._insert_block_labels(ail_graph)
|
|
@@ -1000,6 +1001,7 @@ class Clinic(Analysis):
|
|
|
1000
1001
|
kb=tmp_kb,
|
|
1001
1002
|
track_sp=False,
|
|
1002
1003
|
func_args=arg_list,
|
|
1004
|
+
unify_variables=False,
|
|
1003
1005
|
)
|
|
1004
1006
|
# get ground-truth types
|
|
1005
1007
|
var_manager = tmp_kb.variables[self.function.addr]
|
|
@@ -1284,6 +1286,148 @@ class Clinic(Analysis):
|
|
|
1284
1286
|
|
|
1285
1287
|
return graph
|
|
1286
1288
|
|
|
1289
|
+
def _rewrite_ite_expressions(self, ail_graph):
|
|
1290
|
+
for block in list(ail_graph):
|
|
1291
|
+
ite_ins_addrs = []
|
|
1292
|
+
for stmt in block.statements:
|
|
1293
|
+
if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.ITE):
|
|
1294
|
+
if stmt.ins_addr not in ite_ins_addrs:
|
|
1295
|
+
ite_ins_addrs.append(stmt.ins_addr)
|
|
1296
|
+
|
|
1297
|
+
if ite_ins_addrs:
|
|
1298
|
+
block_addr = block.addr
|
|
1299
|
+
for ite_ins_addr in ite_ins_addrs:
|
|
1300
|
+
block_addr = self._create_triangle_for_ite_expression(ail_graph, block_addr, ite_ins_addr)
|
|
1301
|
+
if block_addr is None or block_addr >= block.addr + block.original_size:
|
|
1302
|
+
break
|
|
1303
|
+
|
|
1304
|
+
def _create_triangle_for_ite_expression(self, ail_graph, block_addr: int, ite_ins_addr: int):
|
|
1305
|
+
# lift the ite instruction to get its size
|
|
1306
|
+
ite_insn_size = self.project.factory.block(ite_ins_addr, num_inst=1).size
|
|
1307
|
+
if ite_insn_size <= 1: # we need an address for true_block and another address for false_block
|
|
1308
|
+
return None
|
|
1309
|
+
|
|
1310
|
+
# relift the head and the ITE instruction
|
|
1311
|
+
new_head = self.project.factory.block(
|
|
1312
|
+
block_addr, size=ite_ins_addr - block_addr + ite_insn_size, cross_insn_opt=False
|
|
1313
|
+
)
|
|
1314
|
+
new_head_ail = ailment.IRSBConverter.convert(new_head.vex, self._ail_manager)
|
|
1315
|
+
# remove all statements between the ITE expression and the very end of the block
|
|
1316
|
+
ite_expr_stmt_idx = None
|
|
1317
|
+
ite_expr_stmt = None
|
|
1318
|
+
for idx, stmt in enumerate(new_head_ail.statements):
|
|
1319
|
+
if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.ITE):
|
|
1320
|
+
ite_expr_stmt_idx = idx
|
|
1321
|
+
ite_expr_stmt = stmt
|
|
1322
|
+
break
|
|
1323
|
+
if ite_expr_stmt_idx is None:
|
|
1324
|
+
return None
|
|
1325
|
+
|
|
1326
|
+
ite_expr: ailment.Expr.ITE = ite_expr_stmt.src
|
|
1327
|
+
new_head_ail.statements = new_head_ail.statements[:ite_expr_stmt_idx]
|
|
1328
|
+
# build the conditional jump
|
|
1329
|
+
true_block_addr = ite_ins_addr
|
|
1330
|
+
false_block_addr = ite_ins_addr + 1
|
|
1331
|
+
cond_jump_stmt = ailment.Stmt.ConditionalJump(
|
|
1332
|
+
ite_expr_stmt.idx,
|
|
1333
|
+
ite_expr.cond,
|
|
1334
|
+
ailment.Expr.Const(None, None, true_block_addr, self.project.arch.bits),
|
|
1335
|
+
ailment.Expr.Const(None, None, false_block_addr, self.project.arch.bits),
|
|
1336
|
+
**ite_expr_stmt.tags,
|
|
1337
|
+
)
|
|
1338
|
+
new_head_ail.statements.append(cond_jump_stmt)
|
|
1339
|
+
|
|
1340
|
+
# build the true block
|
|
1341
|
+
true_block = self.project.factory.block(ite_ins_addr, num_inst=1)
|
|
1342
|
+
true_block_ail = ailment.IRSBConverter.convert(true_block.vex, self._ail_manager)
|
|
1343
|
+
true_block_ail.addr = true_block_addr
|
|
1344
|
+
|
|
1345
|
+
ite_expr_stmt_idx = None
|
|
1346
|
+
ite_expr_stmt = None
|
|
1347
|
+
for idx, stmt in enumerate(true_block_ail.statements):
|
|
1348
|
+
if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.ITE):
|
|
1349
|
+
ite_expr_stmt_idx = idx
|
|
1350
|
+
ite_expr_stmt = stmt
|
|
1351
|
+
break
|
|
1352
|
+
if ite_expr_stmt_idx is None:
|
|
1353
|
+
return None
|
|
1354
|
+
|
|
1355
|
+
true_block_ail.statements[ite_expr_stmt_idx] = ailment.Stmt.Assignment(
|
|
1356
|
+
ite_expr_stmt.idx, ite_expr_stmt.dst, ite_expr_stmt.src.iftrue, **ite_expr_stmt.tags
|
|
1357
|
+
)
|
|
1358
|
+
|
|
1359
|
+
# build the false block
|
|
1360
|
+
false_block = self.project.factory.block(ite_ins_addr, num_inst=1)
|
|
1361
|
+
false_block_ail = ailment.IRSBConverter.convert(false_block.vex, self._ail_manager)
|
|
1362
|
+
false_block_ail.addr = false_block_addr
|
|
1363
|
+
|
|
1364
|
+
ite_expr_stmt_idx = None
|
|
1365
|
+
ite_expr_stmt = None
|
|
1366
|
+
for idx, stmt in enumerate(false_block_ail.statements):
|
|
1367
|
+
if isinstance(stmt, ailment.Stmt.Assignment) and isinstance(stmt.src, ailment.Expr.ITE):
|
|
1368
|
+
ite_expr_stmt_idx = idx
|
|
1369
|
+
ite_expr_stmt = stmt
|
|
1370
|
+
break
|
|
1371
|
+
if ite_expr_stmt_idx is None:
|
|
1372
|
+
return None
|
|
1373
|
+
|
|
1374
|
+
false_block_ail.statements[ite_expr_stmt_idx] = ailment.Stmt.Assignment(
|
|
1375
|
+
ite_expr_stmt.idx, ite_expr_stmt.dst, ite_expr_stmt.src.iffalse, **ite_expr_stmt.tags
|
|
1376
|
+
)
|
|
1377
|
+
|
|
1378
|
+
original_block = next(iter(b for b in ail_graph if b.addr == block_addr))
|
|
1379
|
+
|
|
1380
|
+
original_block_in_edges = list(ail_graph.in_edges(original_block))
|
|
1381
|
+
original_block_out_edges = list(ail_graph.out_edges(original_block))
|
|
1382
|
+
|
|
1383
|
+
# build the target block if the target block does not exist in the current function
|
|
1384
|
+
end_block_addr = ite_ins_addr + ite_insn_size
|
|
1385
|
+
if block_addr < end_block_addr < block_addr + original_block.original_size:
|
|
1386
|
+
end_block = self.project.factory.block(
|
|
1387
|
+
ite_ins_addr + ite_insn_size,
|
|
1388
|
+
size=block_addr + original_block.original_size - (ite_ins_addr + ite_insn_size),
|
|
1389
|
+
cross_insn_opt=False,
|
|
1390
|
+
)
|
|
1391
|
+
end_block_ail = ailment.IRSBConverter.convert(end_block.vex, self._ail_manager)
|
|
1392
|
+
else:
|
|
1393
|
+
end_block_ail = next(iter(b for b in ail_graph if b.addr == end_block_addr))
|
|
1394
|
+
|
|
1395
|
+
# last check: if the first instruction of the end block has Sar, then we bail (due to the peephole optimization
|
|
1396
|
+
# SarToSignedDiv)
|
|
1397
|
+
for stmt in end_block_ail.statements:
|
|
1398
|
+
if stmt.ins_addr > end_block_ail.addr:
|
|
1399
|
+
break
|
|
1400
|
+
if (
|
|
1401
|
+
isinstance(stmt, ailment.Stmt.Assignment)
|
|
1402
|
+
and isinstance(stmt.src, ailment.Expr.BinaryOp)
|
|
1403
|
+
and stmt.src.op == "Sar"
|
|
1404
|
+
):
|
|
1405
|
+
return None
|
|
1406
|
+
|
|
1407
|
+
ail_graph.remove_node(original_block)
|
|
1408
|
+
|
|
1409
|
+
if end_block_ail not in ail_graph:
|
|
1410
|
+
# newly created. add it and the necessary edges into the graph
|
|
1411
|
+
for _, dst in original_block_out_edges:
|
|
1412
|
+
if dst is original_block:
|
|
1413
|
+
ail_graph.add_edge(end_block_ail, new_head_ail)
|
|
1414
|
+
else:
|
|
1415
|
+
ail_graph.add_edge(end_block_ail, dst)
|
|
1416
|
+
|
|
1417
|
+
# in edges
|
|
1418
|
+
for src, _ in original_block_in_edges:
|
|
1419
|
+
if src is original_block:
|
|
1420
|
+
raise ValueError("Unexpected...")
|
|
1421
|
+
ail_graph.add_edge(src, new_head_ail)
|
|
1422
|
+
|
|
1423
|
+
# triangle
|
|
1424
|
+
ail_graph.add_edge(new_head_ail, true_block_ail)
|
|
1425
|
+
ail_graph.add_edge(new_head_ail, false_block_ail)
|
|
1426
|
+
ail_graph.add_edge(true_block_ail, end_block_ail)
|
|
1427
|
+
ail_graph.add_edge(false_block_ail, end_block_ail)
|
|
1428
|
+
|
|
1429
|
+
return end_block_ail.addr
|
|
1430
|
+
|
|
1287
1431
|
@staticmethod
|
|
1288
1432
|
def _remove_redundant_jump_blocks(ail_graph):
|
|
1289
1433
|
def first_conditional_jump(block: ailment.Block) -> Optional[ailment.Stmt.ConditionalJump]:
|
|
@@ -93,7 +93,8 @@ _ail2claripy_op_mapping = {
|
|
|
93
93
|
"Div": lambda expr, conv, _: conv(expr.operands[0], nobool=True) / conv(expr.operands[1], nobool=True),
|
|
94
94
|
"Mod": lambda expr, conv, _: conv(expr.operands[0], nobool=True) % conv(expr.operands[1], nobool=True),
|
|
95
95
|
"Not": lambda expr, conv, _: claripy.Not(conv(expr.operand)),
|
|
96
|
-
"Neg": lambda expr, conv, _:
|
|
96
|
+
"Neg": lambda expr, conv, _: -conv(expr.operand),
|
|
97
|
+
"BitwiseNeg": lambda expr, conv, _: ~conv(expr.operand),
|
|
97
98
|
"Xor": lambda expr, conv, _: conv(expr.operands[0], nobool=True) ^ conv(expr.operands[1], nobool=True),
|
|
98
99
|
"And": lambda expr, conv, _: conv(expr.operands[0], nobool=True) & conv(expr.operands[1], nobool=True),
|
|
99
100
|
"Or": lambda expr, conv, _: conv(expr.operands[0], nobool=True) | conv(expr.operands[1], nobool=True),
|
|
@@ -642,7 +643,8 @@ class ConditionProcessor:
|
|
|
642
643
|
|
|
643
644
|
_mapping = {
|
|
644
645
|
"Not": lambda cond_, tags: _unary_op_reduce("Not", cond_.args[0], tags),
|
|
645
|
-
"
|
|
646
|
+
"__neg__": lambda cond_, tags: _unary_op_reduce("Not", cond_.args[0], tags),
|
|
647
|
+
"__invert__": lambda cond_, tags: _unary_op_reduce("BitwiseNeg", cond_.args[0], tags),
|
|
646
648
|
"And": lambda cond_, tags: _binary_op_reduce("LogicalAnd", cond_.args, tags),
|
|
647
649
|
"Or": lambda cond_, tags: _binary_op_reduce("LogicalOr", cond_.args, tags),
|
|
648
650
|
"__le__": lambda cond_, tags: _binary_op_reduce("CmpLE", cond_.args, tags, signed=True),
|
|
@@ -88,6 +88,8 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
|
|
|
88
88
|
expr.signed,
|
|
89
89
|
**expr.tags,
|
|
90
90
|
)
|
|
91
|
+
if isinstance(expr.operands[0], Const) and expr.operands[0].value == 0:
|
|
92
|
+
return UnaryOp(expr.idx, "Neg", expr.operands[1], **expr.tags)
|
|
91
93
|
|
|
92
94
|
elif expr.op == "And":
|
|
93
95
|
if isinstance(expr.operands[0], Const) and isinstance(expr.operands[1], Const):
|
|
@@ -829,12 +829,13 @@ class CForLoop(CStatement):
|
|
|
829
829
|
yield from self.iterator.c_repr_chunks(indent=0, asexpr=True)
|
|
830
830
|
yield ")", paren
|
|
831
831
|
|
|
832
|
-
if self.codegen.braces_on_own_lines:
|
|
833
|
-
yield "\n", None
|
|
834
|
-
yield indent_str, None
|
|
835
|
-
else:
|
|
836
|
-
yield " ", None
|
|
837
832
|
if self.body is not None:
|
|
833
|
+
if self.codegen.braces_on_own_lines:
|
|
834
|
+
yield "\n", None
|
|
835
|
+
yield indent_str, None
|
|
836
|
+
else:
|
|
837
|
+
yield " ", None
|
|
838
|
+
|
|
838
839
|
yield "{", brace
|
|
839
840
|
yield "\n", None
|
|
840
841
|
yield from self.body.c_repr_chunks(indent=indent + INDENT_DELTA)
|
|
@@ -937,17 +938,12 @@ class CIfElse(CStatement):
|
|
|
937
938
|
yield from self.else_node.c_repr_chunks(indent=indent)
|
|
938
939
|
else:
|
|
939
940
|
if single_stmt_else:
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
yield indent_str, None
|
|
941
|
+
yield indent_str, None
|
|
942
|
+
elif self.codegen.braces_on_own_lines:
|
|
943
|
+
yield "\n", None
|
|
944
|
+
yield indent_str, None
|
|
945
945
|
else:
|
|
946
|
-
|
|
947
|
-
yield "\n", None
|
|
948
|
-
yield indent_str, None
|
|
949
|
-
else:
|
|
950
|
-
yield " ", None
|
|
946
|
+
yield " ", None
|
|
951
947
|
|
|
952
948
|
yield "else", self
|
|
953
949
|
if self.codegen.braces_on_own_lines or single_stmt_else:
|
|
@@ -1580,6 +1576,7 @@ class CUnaryOp(CExpression):
|
|
|
1580
1576
|
OP_MAP = {
|
|
1581
1577
|
"Not": self._c_repr_chunks_not,
|
|
1582
1578
|
"Neg": self._c_repr_chunks_neg,
|
|
1579
|
+
"BitwiseNeg": self._c_repr_chunks_bitwiseneg,
|
|
1583
1580
|
"Reference": self._c_repr_chunks_reference,
|
|
1584
1581
|
"Dereference": self._c_repr_chunks_dereference,
|
|
1585
1582
|
}
|
|
@@ -1601,13 +1598,20 @@ class CUnaryOp(CExpression):
|
|
|
1601
1598
|
yield from CExpression._try_c_repr_chunks(self.operand)
|
|
1602
1599
|
yield ")", paren
|
|
1603
1600
|
|
|
1604
|
-
def
|
|
1601
|
+
def _c_repr_chunks_bitwiseneg(self):
|
|
1605
1602
|
paren = CClosingObject("(")
|
|
1606
1603
|
yield "~", self
|
|
1607
1604
|
yield "(", paren
|
|
1608
1605
|
yield from CExpression._try_c_repr_chunks(self.operand)
|
|
1609
1606
|
yield ")", paren
|
|
1610
1607
|
|
|
1608
|
+
def _c_repr_chunks_neg(self):
|
|
1609
|
+
paren = CClosingObject("(")
|
|
1610
|
+
yield "-", self
|
|
1611
|
+
yield "(", paren
|
|
1612
|
+
yield from CExpression._try_c_repr_chunks(self.operand)
|
|
1613
|
+
yield ")", paren
|
|
1614
|
+
|
|
1611
1615
|
def _c_repr_chunks_reference(self):
|
|
1612
1616
|
yield "&", self
|
|
1613
1617
|
yield from CExpression._try_c_repr_chunks(self.operand)
|
|
@@ -13,7 +13,7 @@ from ailment.expression import Const, UnaryOp, MultiStatementExpression
|
|
|
13
13
|
from angr.utils.graph import GraphUtils
|
|
14
14
|
from ....knowledge_plugins.cfg import IndirectJumpType
|
|
15
15
|
from ....utils.constants import SWITCH_MISSING_DEFAULT_NODE_ADDR
|
|
16
|
-
from ....utils.graph import dominates,
|
|
16
|
+
from ....utils.graph import dominates, to_acyclic_graph
|
|
17
17
|
from ..sequence_walker import SequenceWalker
|
|
18
18
|
from ..utils import (
|
|
19
19
|
remove_last_statement,
|
|
@@ -1913,21 +1913,16 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1913
1913
|
other_edges = []
|
|
1914
1914
|
idoms = networkx.immediate_dominators(full_graph, head)
|
|
1915
1915
|
if networkx.is_directed_acyclic_graph(full_graph):
|
|
1916
|
-
_, inv_idoms = inverted_idoms(full_graph)
|
|
1917
1916
|
acyclic_graph = full_graph
|
|
1918
1917
|
else:
|
|
1919
1918
|
acyclic_graph = to_acyclic_graph(full_graph, loop_heads=[head])
|
|
1920
|
-
_, inv_idoms = inverted_idoms(acyclic_graph)
|
|
1921
1919
|
for src, dst in acyclic_graph.edges:
|
|
1922
1920
|
if src is dst:
|
|
1923
1921
|
continue
|
|
1924
|
-
if not
|
|
1925
|
-
# the edge might be from full_graph but not in graph
|
|
1926
|
-
continue
|
|
1927
|
-
if not dominates(idoms, src, dst) and not dominates(inv_idoms, dst, src):
|
|
1922
|
+
if not dominates(idoms, src, dst) and not dominates(idoms, dst, src):
|
|
1928
1923
|
if (src.addr, dst.addr) not in self.whitelist_edges:
|
|
1929
1924
|
all_edges_wo_dominance.append((src, dst))
|
|
1930
|
-
elif not dominates(idoms, src, dst)
|
|
1925
|
+
elif not dominates(idoms, src, dst):
|
|
1931
1926
|
if (src.addr, dst.addr) not in self.whitelist_edges:
|
|
1932
1927
|
secondary_edges.append((src, dst))
|
|
1933
1928
|
else:
|
|
@@ -1935,7 +1930,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
1935
1930
|
other_edges.append((src, dst))
|
|
1936
1931
|
|
|
1937
1932
|
ordered_nodes = GraphUtils.quasi_topological_sort_nodes(acyclic_graph, loop_heads=[head])
|
|
1938
|
-
node_seq = {nn: idx for (idx, nn) in enumerate(ordered_nodes)}
|
|
1933
|
+
node_seq = {nn: (len(ordered_nodes) - idx) for (idx, nn) in enumerate(ordered_nodes)} # post-order
|
|
1939
1934
|
|
|
1940
1935
|
if all_edges_wo_dominance:
|
|
1941
1936
|
all_edges_wo_dominance = self._chick_order_edges(all_edges_wo_dominance, node_seq)
|
|
@@ -2008,7 +2003,8 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2008
2003
|
)
|
|
2009
2004
|
new_src = SequenceNode(src.addr, nodes=[src, goto_node])
|
|
2010
2005
|
|
|
2011
|
-
graph.
|
|
2006
|
+
if graph.has_edge(src, dst):
|
|
2007
|
+
graph.remove_edge(src, dst)
|
|
2012
2008
|
if new_src is not None:
|
|
2013
2009
|
self.replace_nodes(graph, src, new_src)
|
|
2014
2010
|
if full_graph is not None:
|
angr/analyses/disassembly.py
CHANGED
|
@@ -214,10 +214,6 @@ class Instruction(DisassemblyPiece):
|
|
|
214
214
|
assert hasattr(self.insn, "operands")
|
|
215
215
|
|
|
216
216
|
op_str = self.insn.op_str
|
|
217
|
-
# NOTE: the size of dummy_operands is not necessarily equal to
|
|
218
|
-
# operands count of capstone disasm result. If we check
|
|
219
|
-
# len(self.operands) == len(self.insn.operands)
|
|
220
|
-
# special cases in arm disassembly will mess up the code
|
|
221
217
|
dummy_operands = self.split_arm_op_string(op_str)
|
|
222
218
|
|
|
223
219
|
for operand in dummy_operands:
|
|
@@ -278,16 +274,16 @@ class Instruction(DisassemblyPiece):
|
|
|
278
274
|
|
|
279
275
|
@staticmethod
|
|
280
276
|
def split_arm_op_string(op_str: str):
|
|
281
|
-
# Split arm operand string
|
|
277
|
+
# Split arm operand string with commas outside the square brackets
|
|
282
278
|
pieces = []
|
|
283
|
-
|
|
279
|
+
in_square_brackets = False
|
|
284
280
|
cur_opr = ""
|
|
285
281
|
for c in op_str:
|
|
286
|
-
if c == "["
|
|
287
|
-
|
|
288
|
-
if c == "]"
|
|
289
|
-
|
|
290
|
-
if c == "," and
|
|
282
|
+
if c == "[":
|
|
283
|
+
in_square_brackets = True
|
|
284
|
+
if c == "]":
|
|
285
|
+
in_square_brackets = False
|
|
286
|
+
if c == "," and not in_square_brackets:
|
|
291
287
|
pieces.append(cur_opr)
|
|
292
288
|
cur_opr = ""
|
|
293
289
|
continue
|
|
@@ -5,13 +5,13 @@ import logging
|
|
|
5
5
|
import claripy
|
|
6
6
|
from ailment import Stmt, Expr
|
|
7
7
|
|
|
8
|
-
from angr.errors import SimMemoryMissingError
|
|
9
8
|
from angr.knowledge_plugins.propagations.prop_value import PropValue, Detail
|
|
10
9
|
from angr.analyses.reaching_definitions.external_codeloc import ExternalCodeLocation
|
|
10
|
+
from angr.knowledge_plugins.key_definitions.atoms import Register
|
|
11
11
|
from ...utils.constants import is_alignment_mask
|
|
12
12
|
from ...engines.light import SimEngineLightAILMixin
|
|
13
13
|
from ...sim_variable import SimStackVariable, SimMemoryVariable
|
|
14
|
-
from ..reaching_definitions.reaching_definitions import OP_BEFORE
|
|
14
|
+
from ..reaching_definitions.reaching_definitions import OP_BEFORE
|
|
15
15
|
from .engine_base import SimEnginePropagatorBase
|
|
16
16
|
|
|
17
17
|
if TYPE_CHECKING:
|
|
@@ -378,26 +378,17 @@ class SimEnginePropagatorAIL(
|
|
|
378
378
|
reg_defat = None
|
|
379
379
|
if self._reaching_definitions is not None:
|
|
380
380
|
codeloc = self._codeloc()
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
reg_defat = next(iter(reg_defat_codelocs))
|
|
393
|
-
defat_key = "stmt", (reg_defat.block_addr, reg_defat.block_idx, reg_defat.stmt_idx), OP_BEFORE
|
|
394
|
-
if defat_key not in self._reaching_definitions.observed_results:
|
|
395
|
-
# the observation point does not exist. probably it's because te observation point is in a
|
|
396
|
-
# callee function.
|
|
397
|
-
reg_defat = None
|
|
398
|
-
if isinstance(reg_defat, ExternalCodeLocation):
|
|
399
|
-
# there won't be an observed result for external code location. give up
|
|
400
|
-
reg_defat = None
|
|
381
|
+
reg_defat_defs = self._reaching_definitions.get_defs(
|
|
382
|
+
Register(expr.reg_offset, expr.size), codeloc, OP_BEFORE
|
|
383
|
+
)
|
|
384
|
+
reg_defat_codelocs = {reg_def.codeloc for reg_def in reg_defat_defs}
|
|
385
|
+
if len(reg_defat_codelocs) == 1:
|
|
386
|
+
reg_defat = next(iter(reg_defat_codelocs))
|
|
387
|
+
if reg_defat.stmt_idx is None:
|
|
388
|
+
# the observation point is in a callee function
|
|
389
|
+
reg_defat = None
|
|
390
|
+
if isinstance(reg_defat, ExternalCodeLocation):
|
|
391
|
+
reg_defat = None
|
|
401
392
|
|
|
402
393
|
if new_expr is not None:
|
|
403
394
|
# check if this new_expr uses any expression that has been overwritten
|
|
@@ -1139,36 +1130,17 @@ class SimEnginePropagatorAIL(
|
|
|
1139
1130
|
l.warning("Unknown where the expression is defined. Assume the definition is out-dated.")
|
|
1140
1131
|
return True, False
|
|
1141
1132
|
|
|
1142
|
-
key_defat = "stmt", (expr_defat.block_addr, expr_defat.block_idx, expr_defat.stmt_idx), OP_AFTER
|
|
1143
|
-
if key_defat not in self._reaching_definitions.observed_results:
|
|
1144
|
-
l.warning(
|
|
1145
|
-
"Required reaching definition state at instruction address %#x is not found. Assume the definition is "
|
|
1146
|
-
"out-dated.",
|
|
1147
|
-
expr_defat.ins_addr,
|
|
1148
|
-
)
|
|
1149
|
-
return True, False
|
|
1150
|
-
|
|
1151
|
-
key_currloc = "stmt", (current_loc.block_addr, current_loc.block_idx, current_loc.stmt_idx), OP_BEFORE
|
|
1152
|
-
if key_currloc not in self._reaching_definitions.observed_results:
|
|
1153
|
-
l.warning(
|
|
1154
|
-
"Required reaching definition state at instruction address %#x is not found. Assume the definition is "
|
|
1155
|
-
"out-dated.",
|
|
1156
|
-
current_loc.ins_addr,
|
|
1157
|
-
)
|
|
1158
|
-
return True, False
|
|
1159
|
-
|
|
1160
1133
|
from .outdated_definition_walker import OutdatedDefinitionWalker # pylint:disable=import-outside-toplevel
|
|
1161
1134
|
|
|
1162
1135
|
walker = OutdatedDefinitionWalker(
|
|
1163
1136
|
expr,
|
|
1164
1137
|
expr_defat,
|
|
1165
|
-
self._reaching_definitions.observed_results[key_defat],
|
|
1166
1138
|
current_loc,
|
|
1167
|
-
self._reaching_definitions.observed_results[key_currloc],
|
|
1168
1139
|
self.state,
|
|
1169
1140
|
self.arch,
|
|
1170
1141
|
avoid=avoid,
|
|
1171
1142
|
extract_offset_to_sp=self.extract_offset_to_sp,
|
|
1143
|
+
rda=self._reaching_definitions,
|
|
1172
1144
|
)
|
|
1173
1145
|
walker.walk_expression(expr)
|
|
1174
1146
|
return walker.out_dated, walker.has_avoid
|