summaryrefslogtreecommitdiff
path: root/pwnlib/shellcraft/templates/mips/mov.asm
blob: 28e3c77fe7209b2aaa09f20588334cff8c2efb1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<%
  from pwnlib.util import lists, packing, fiddling, misc
  from pwnlib.constants import eval, Constant
  from pwnlib.context import context as ctx # Ugly hack, mako will not let it be called context
  from pwnlib.log import getLogger
  from pwnlib.shellcraft import mips, registers, pretty, okay
  import six
  log = getLogger('pwnlib.shellcraft.mips.mov')
%>
<%page args="dst, src"/>
<%docstring>
Move src into dst without newlines and null bytes.

Registers $t8 and $t9 are not guaranteed to be preserved.

If src is a string that is not a register, then it will locally set
`context.arch` to `'mips'` and use :func:`pwnlib.constants.eval` to evaluate the
string. Note that this means that this shellcode can change behavior depending
on the value of `context.os`.

Args:

  dst (str): The destination register.
  src (str): Either the input register, or an immediate value.

Example:

    >>> print(shellcraft.mips.mov('$t0', 0).rstrip())
        slti $t0, $zero, 0xFFFF /* $t0 = 0 */
    >>> print(shellcraft.mips.mov('$t2', 0).rstrip())
        xor $t2, $t2, $t2  /* $t2 = 0 */
    >>> print(shellcraft.mips.mov('$t0', 0xcafebabe).rstrip())
        li $t0, 0xcafebabe
    >>> print(shellcraft.mips.mov('$t2', 0xcafebabe).rstrip())
        li $t9, 0xcafebabe
        add $t2, $t9, $zero
    >>> print(shellcraft.mips.mov('$s0', 0xca0000be).rstrip())
        li $t9, ~0xca0000be
        not $s0, $t9
    >>> print(shellcraft.mips.mov('$s0', 0xca0000ff).rstrip())
        li $t9, 0x1010101 ^ 0xca0000ff
        li $s0, 0x1010101
        xor $s0, $t9, $s0
    >>> print(shellcraft.mips.mov('$t9', 0xca0000be).rstrip())
        li $t9, ~0xca0000be
        not $t9, $t9
    >>> print(shellcraft.mips.mov('$t2', 0xca0000be).rstrip())
        li $t9, ~0xca0000be
        not $t9, $t9
        add $t2, $t9, $0 /* mov $t2, $t9 */
    >>> print(shellcraft.mips.mov('$t2', 0xca0000ff).rstrip())
        li $t8, 0x1010101 ^ 0xca0000ff
        li $t9, 0x1010101
        xor $t9, $t8, $t9
        add $t2, $t9, $0 /* mov $t2, $t9 */
    >>> print(shellcraft.mips.mov('$a0', '$t2').rstrip())
        add $a0, $t2, $0 /* mov $a0, $t2 */
    >>> print(shellcraft.mips.mov('$a0', '$t8').rstrip())
        sw $t8, -4($sp) /* mov $a0, $t8 */
        lw $a0, -4($sp)

</%docstring>
<%
if isinstance(src, str) and src.startswith('$') and src not in registers.mips:
    log.error("Unknown register %r" % src)
    return

if not dst.startswith('$'):
    log.error("Registers must start with $")
    return

if isinstance(dst, str) and dst.startswith('$') and dst not in registers.mips:
    log.error("Unknown register %r" % dst)
    return

if isinstance(src, str) and src not in registers.mips:
    src = eval(src)

src_reg = registers.mips.get(src, None)
dst_reg = registers.mips.get(dst, None)
tmp_reg = '$t9' if dst_reg != registers.mips['$t9'] else '$t8'

if src_reg == 0:
    src = 0
    src_reg = None
%>\
% if None not in (src_reg, dst_reg):
    % if src_reg == dst_reg:
## Nop.
    /* mov ${dst}, ${src} is a noop */
    % elif src_reg not in [2, 3, 4, 5, 6, 7, 8, 16, 24]:
## Avoid using a src in the list because it causes NULL byte
    add ${dst}, ${src}, $0 /* mov ${dst}, ${src} */
    % else:
## Better than two 'li' instructions due to being two instructions
## fewer. 'li' is actually 'lui' and 'ori' in hiding.
    sw ${src}, -4($sp) /* mov ${dst}, ${src} */
    lw ${dst}, -4($sp)
    % endif
% elif dst_reg == 10:
## Register $t2/$10 may encodes a newline for 'lui $t2, XXXX'
## so we have to send everything through $t9.
    %if okay(src):
    li $t9, ${pretty(src)}
    add ${dst}, $t9, $zero
    % elif src in (0, '$zero', '$0'):
    xor ${dst}, ${dst}, ${dst}  /* ${dst} = 0 */
    % elif dst == '$t2':
    ${mips.mov('$t9', src)}
    ${mips.mov(dst, '$t9')}
    %endif
% elif isinstance(src, six.integer_types):
## Everything else is the general case for moving into registers.
<%
    srcp = packing.pack(src, word_size=32)
    srcu = packing.unpack(srcp, word_size=32, sign=False)
%>
% if src in (0, '$zero', '$0'):
## XOR sometimes encodes a zero byte, so use SLTI instead
    slti ${dst}, $zero, 0xFFFF /* ${dst} = 0 */
% elif okay(src):
## Nice and easy
    li ${dst}, ${pretty(src)}
% elif 0 < src <= 0xffff and okay(src, bytes=2):
    ori ${dst}, $zero, ${src}
% elif okay((~srcu) & 0xffffffff):
## Almost nice and easy
    li $t9, ~${pretty(src)}
    not ${dst}, $t9
% else:
<%
a,b = fiddling.xor_pair(srcp, avoid = '\x00\n')
a = hex(packing.unpack(a, 32))
b = hex(packing.unpack(b, 32))
%>
    li ${tmp_reg}, ${a} ^ ${pretty(src)}
    li ${dst}, ${a}
    xor ${dst}, ${tmp_reg}, ${dst}
% endif
% endif