mirror of
https://github.com/angr/angr
synced 2026-08-17 12:23:11 -04:00
* VariableMap: Track Call prototype and calling_convention. * Lint code. * Fix two _handle_stmt_SideEffectStatement.
179 lines
5.2 KiB
Python
179 lines
5.2 KiB
Python
#!/usr/bin/env python3
|
|
# pylint:disable=missing-class-docstring,no-self-use
|
|
from __future__ import annotations
|
|
|
|
__package__ = __package__ or "tests.analyses.decompiler" # pylint:disable=redefined-builtin
|
|
|
|
import logging
|
|
import unittest
|
|
|
|
import networkx as nx
|
|
|
|
import angr
|
|
from angr.ailment import Assignment, BinaryOp, Block, Const, Register
|
|
from angr.ailment.expression import Call
|
|
from angr.ailment.manager import Manager
|
|
from angr.ailment.statement import ConditionalJump, Return, Store
|
|
from angr.analyses.decompiler.optimization_passes import FlipBooleanCmp
|
|
from angr.analyses.decompiler.structurer_nodes import ConditionNode, SequenceNode
|
|
|
|
log = logging.getLogger(__name__)
|
|
# log.setLevel(logging.DEBUG)
|
|
|
|
|
|
def c(v):
|
|
"""Simple AIL Const shorthand"""
|
|
return Const(0, v, 32)
|
|
|
|
|
|
def r(o):
|
|
"""Simple AIL Register shorthand"""
|
|
return Register(0, o, 32)
|
|
|
|
|
|
class TestFlipBooleanCmp(unittest.TestCase):
|
|
"""
|
|
Test FlipBooleanCmp optimization pass.
|
|
"""
|
|
|
|
def test_type2_store_not_moved(self):
|
|
"""
|
|
Ensure that:
|
|
|
|
v0 = 123;
|
|
if (v0 <= 1000)
|
|
v0 = 456;
|
|
g_deadbeef = v0;
|
|
return;
|
|
|
|
is not mistakenly transformed to:
|
|
|
|
v0 = 123;
|
|
if (v0 > 1000) {
|
|
g_deadbeef = v0;
|
|
return;
|
|
}
|
|
v0 = 456;
|
|
"""
|
|
flip_size = 1
|
|
|
|
block_0 = Block(
|
|
0x400000,
|
|
1,
|
|
[
|
|
Assignment(0, r(0), c(0x123)),
|
|
ConditionalJump(
|
|
1, BinaryOp(2, "CmpLE", [r(0), c(0x1000)], False), c(0x400023), c(0x400037), ins_addr=0x400001
|
|
),
|
|
],
|
|
)
|
|
block_1 = Block(0x400023, 1, [Assignment(3, r(0), c(0x456)) for _ in range(flip_size)])
|
|
block_2 = Block(
|
|
0x400037,
|
|
1,
|
|
[
|
|
Store(4, c(0xDEADBEEF), r(0), 4, "Iend_LE"), # Must not be moved
|
|
Return(5, []),
|
|
],
|
|
)
|
|
|
|
graph = nx.DiGraph()
|
|
graph.add_edges_from([(block_0, block_1), (block_0, block_2), (block_1, block_2)])
|
|
|
|
func = None
|
|
proj = angr.load_shellcode(b"\x90\x90", "AMD64")
|
|
ri = proj.analyses.RegionIdentifier(func, graph=graph)
|
|
rs = proj.analyses.RecursiveStructurer(ri.region, ail_manager=Manager())
|
|
seq = rs.result
|
|
|
|
assert isinstance(seq, SequenceNode)
|
|
assert len(seq.nodes) == 3
|
|
assert isinstance(seq.nodes[0], Block)
|
|
assert isinstance(seq.nodes[1], ConditionNode)
|
|
assert isinstance(seq.nodes[2], Block)
|
|
assert isinstance(seq.nodes[2].statements[0], Store)
|
|
assert isinstance(seq.nodes[2].statements[1], Return)
|
|
|
|
pre_transform_seq_repr = seq.dbg_repr()
|
|
log.debug("Before:\n%s", pre_transform_seq_repr)
|
|
|
|
manager = Manager()
|
|
FlipBooleanCmp(func, manager, flip_size=flip_size, seq=seq, graph=graph)
|
|
|
|
post_transform_seq_repr = seq.dbg_repr()
|
|
log.debug("After:\n%s", post_transform_seq_repr)
|
|
|
|
assert pre_transform_seq_repr == post_transform_seq_repr
|
|
|
|
def test_type2_call_not_moved(self):
|
|
"""
|
|
Ensure that:
|
|
|
|
v0 = 123;
|
|
if (v0 <= 1000)
|
|
v0 = 456;
|
|
always_called(v0);
|
|
return;
|
|
|
|
is not mistakenly transformed to:
|
|
|
|
v0 = 123;
|
|
if (v0 > 1000) {
|
|
always_called(v0);
|
|
return;
|
|
}
|
|
v0 = 456;
|
|
"""
|
|
flip_size = 1
|
|
|
|
block_0 = Block(
|
|
0x400000,
|
|
1,
|
|
[
|
|
Assignment(0, r(0), c(0x123)),
|
|
ConditionalJump(
|
|
1, BinaryOp(2, "CmpLE", [r(0), c(0x1000)], False), c(0x400023), c(0x400037), ins_addr=0x400001
|
|
),
|
|
],
|
|
)
|
|
block_1 = Block(0x400023, 1, [Assignment(3, r(0), c(0x456)) for _ in range(flip_size)])
|
|
block_2 = Block(
|
|
0x400037,
|
|
1,
|
|
[
|
|
Call(4, "always_called", [r(0)]), # Must not be moved
|
|
Return(5, []),
|
|
],
|
|
)
|
|
|
|
graph = nx.DiGraph()
|
|
graph.add_edges_from([(block_0, block_1), (block_0, block_2), (block_1, block_2)])
|
|
|
|
func = None
|
|
proj = angr.load_shellcode(b"\x90\x90", "AMD64")
|
|
ri = proj.analyses.RegionIdentifier(func, graph=graph)
|
|
rs = proj.analyses.RecursiveStructurer(ri.region, ail_manager=Manager())
|
|
seq = rs.result
|
|
|
|
assert isinstance(seq, SequenceNode)
|
|
assert len(seq.nodes) == 3
|
|
assert isinstance(seq.nodes[0], Block)
|
|
assert isinstance(seq.nodes[1], ConditionNode)
|
|
assert isinstance(seq.nodes[2], Block)
|
|
assert isinstance(seq.nodes[2].statements[0], Call)
|
|
assert isinstance(seq.nodes[2].statements[1], Return)
|
|
|
|
pre_transform_seq_repr = seq.dbg_repr()
|
|
log.debug("Before:\n%s", pre_transform_seq_repr)
|
|
|
|
manager = Manager()
|
|
FlipBooleanCmp(func, manager, flip_size=flip_size, seq=seq, graph=graph)
|
|
|
|
post_transform_seq_repr = seq.dbg_repr()
|
|
log.debug("After:\n%s", post_transform_seq_repr)
|
|
|
|
assert pre_transform_seq_repr == post_transform_seq_repr
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|