pwnlib.shellcraft.riscv64 — Shellcode for RISCV64

pwnlib.shellcraft.riscv64

Shellcraft module containing generic RISCV64 shellcodes.

pwnlib.shellcraft.riscv64.mov(dst, src, c=False)[source]

Move src into dst without newlines and null bytes.

Registers t4 and t6 are not guaranteed to be preserved.

If src is a string that is not a register, then it will locally set context.arch to ‘riscv64’ and use pwnlib.constants.eval() to evaluate the string. Note that this means that this shellcode can change behavior depending on the value of context.os.

Parameters:
  • dst (str) – The destination register.

  • src (str) – Either the input register, or an immediate value.

Example

>>> print(shellcraft.riscv64.mov('t0', 0).rstrip())
    xor t0, t6, t6
>>> print(shellcraft.riscv64.mov('t0', 0x2000, c=True).rstrip())
    c.lui t0, 0xfffff & (0x2000 >> 12)
>>> print(shellcraft.riscv64.mov('t5', 0x601).rstrip())
    xori t5, zero, 0x601
>>> print(shellcraft.riscv64.mov('t5', 0x600).rstrip())
    xori t5, zero, 0x7ff ^ 0x600
    xori t5, t5, 0x7ff
>>> print(shellcraft.riscv64.mov('t6', 0x181f).rstrip())
    lui t6, 0xfffff & (~0x181f >> 12)
    xori t6, t6, ~0x7ff | 0x181f
>>> print(shellcraft.riscv64.mov('t5', 0x40b561f).rstrip())
    lui t5, 0xfffff & (0x40b561f >> 12)
    xori t5, t5, 0x7ff & 0x40b561f
>>> print(shellcraft.riscv64.mov('t0', 0xcafebabe).rstrip())
    li t0, 0xcafebabe
>>> print(shellcraft.riscv64.mov('a0', 't2', c=True).rstrip())
    c.mv a0, t2
>>> print(shellcraft.riscv64.mov('t1', 'sp', c=True).rstrip())
    sra t1, sp, zero
pwnlib.shellcraft.riscv64.nop()[source]

RISCV64 nop instruction.

pwnlib.shellcraft.riscv64.push(value)[source]

Pushes a value onto the stack.

Register t4 is not guaranteed to be preserved.

pwnlib.shellcraft.riscv64.pushstr(string, append_null=True)[source]

Pushes a string onto the stack without using null bytes or newline characters.

Example

>>> print(shellcraft.riscv64.pushstr('').rstrip())
    /* push b'\x00' */
    sw zero, -8(sp)
    addi sp, sp, -8
>>> print(shellcraft.riscv64.pushstr('a').rstrip())
    /* push b'a\x00' */
    xori t4, zero, 0x7ff ^ 0x61
    xori t4, t4, 0x7ff
    sd t4, -8(sp)
    addi sp, sp, -8
>>> print(shellcraft.riscv64.pushstr('aa').rstrip())
    /* push b'aa\x00' */
    lui t4, 0xfffff & (~0x6161 >> 12)
    xori t4, t4, ~0x7ff | 0x6161
    addi t4, t4, -0x800
    sd t4, -8(sp)
    addi sp, sp, -8
>>> print(shellcraft.riscv64.pushstr('aaaa').rstrip())
    /* push b'aaaa\x00' */
    lui t4, 0xfffff & (0x61616161 >> 12)
    xori t4, t4, 0x7ff & 0x61616161
    sd t4, -8(sp)
    addi sp, sp, -8
>>> print(shellcraft.riscv64.pushstr('aaaaa').rstrip())
    /* push b'aaaaa\x00' */
    xori t4, zero, 0x7ff ^ 0x61
    xori t4, t4, 0x7ff
    lui t6, 0xfffff & (0x61616161 >> 12)
    xori t6, t6, 0x7ff & 0x61616161
    slli t4, t4, 0x20
    xor t4, t4, t6
    sd t4, -8(sp)
    addi sp, sp, -8
>>> print(shellcraft.riscv64.pushstr('aaaa', append_null = False).rstrip())
    /* push b'aaaa' */
    lui t4, 0xfffff & (0x61616161 >> 12)
    xori t4, t4, 0x7ff & 0x61616161
    sd t4, -8(sp)
    addi sp, sp, -8
>>> print(shellcraft.riscv64.pushstr(b'\xc3').rstrip())
    /* push b'\xc3\x00' */
    xori t4, zero, 0x7ff ^ 0xc3
    xori t4, t4, 0x7ff
    sd t4, -8(sp)
    addi sp, sp, -8
>>> print(shellcraft.riscv64.pushstr(b'\xc3', append_null = False).rstrip())
    /* push b'\xc3' */
    xori t4, zero, 0x7ff ^ 0xc3
    xori t4, t4, 0x7ff
    sd t4, -8(sp)
    addi sp, sp, -8
>>> print(enhex(asm(shellcraft.riscv64.pushstr("/bin/sh"))))
b78e97ff93cefeb2938e0e80b76f696e93cfff22939e0e02b3cefe01233cd1ff130181ff
>>> print(enhex(asm(shellcraft.riscv64.pushstr(""))))
232c01fe130181ff
>>> print(enhex(asm(shellcraft.riscv64.pushstr("\x00", append_null =  False))))
232c01fe130181ff
Parameters:
  • string (str) – The string to push.

  • append_null (bool) – Whether to append a single NULL-byte before pushing.

pwnlib.shellcraft.riscv64.pushstr_array(reg, array)[source]

Pushes an array/envp-style array of pointers onto the stack.

Parameters:
  • reg (str) – Destination register to hold the pointer.

  • array (str,list) – Single argument or list of arguments to push. NULL termination is normalized so that each argument ends with exactly one NULL byte.

pwnlib.shellcraft.riscv64.setregs(reg_context, stack_allowed=True)[source]

Sets multiple registers, taking any register dependencies into account (i.e., given eax=1,ebx=eax, set ebx first).

Parameters:
  • reg_context (dict) – Desired register context

  • stack_allowed (bool) – Can the stack be used?

Example

>>> print(shellcraft.setregs({'t0':1, 'a3':'0'}).rstrip())
    xor a3, t6, t6
    sltiu t0, zero, 0x7ff | 1
>>> print(shellcraft.setregs({'a0':'a1', 'a1':'a0', 'a2':'a1'}).rstrip())
    sra a2, a1, zero
    sra t4, a1, zero
    xor a1, a0, t4 /* xchg a1, a0 */
    sra t4, a0, zero
    xor a0, a1, t4
    sra t4, a1, zero
    xor a1, a0, t4
pwnlib.shellcraft.riscv64.trap()[source]

A trap instruction.

pwnlib.shellcraft.riscv64.xor(dst, rs1, rs2)[source]

XOR two registers rs1 and rs2, store result in register dst.

Register t4 is not guaranteed to be preserved.

pwnlib.shellcraft.riscv64.linux

Shellcraft module containing RISCV64 shellcodes for Linux.

pwnlib.shellcraft.riscv64.linux.cat2(filename, fd=1, length=16384)[source]

Opens a file and writes its contents to the specified file descriptor. Uses an extra stack buffer and must know the length.

pwnlib.shellcraft.riscv64.linux.kill(pid, sig) str[source]

Invokes the syscall kill.

See ‘man 2 kill’ for more information.

Parameters:
  • pid (pid_t) – pid

  • sig (int) – sig

Returns:

int

pwnlib.shellcraft.riscv64.linux.open(filename, flags=0, mode='a3')[source]

Opens a file

pwnlib.shellcraft.riscv64.linux.sleep(seconds)[source]

Sleeps for the specified amount of seconds.

Uses SYS_nanosleep under the hood. Doesn’t check for interrupts and doesn’t retry with the remaining time.

Parameters:

seconds (int,float) – The time to sleep in seconds.

pwnlib.shellcraft.riscv64.linux.syscall(syscall=None, arg0=None, arg1=None, arg2=None, arg3=None, arg4=None, arg5=None)[source]
Args: [syscall_number, *args]

Does a syscall

Any of the arguments can be expressions to be evaluated by pwnlib.constants.eval().

Example

>>> print(pwnlib.shellcraft.riscv64.linux.syscall('SYS_execve', 1, 'sp', 2, 0).rstrip())
    /* call execve(1, 'sp', 2, 0) */
    sltiu a0, zero, 0x7ff | 1
    sra a1, sp, zero
    xori a2, zero, 0x7ff ^ 2
    xori a2, a2, 0x7ff
    xor a3, t6, t6
    xori a7, zero, 0x7ff ^ SYS_execve /* 0xdd */
    xori a7, a7, 0x7ff
    ecall
>>> print(pwnlib.shellcraft.riscv64.linux.syscall('SYS_execve', 2, 1, 0, 20).rstrip())
    /* call execve(2, 1, 0, 0x14) */
    xori a0, zero, 0x7ff ^ 2
    xori a0, a0, 0x7ff
    sltiu a1, zero, 0x7ff | 1
    xor a2, t6, t6
    xori a3, zero, 0x7ff ^ 0x14
    xori a3, a3, 0x7ff
    xori a7, zero, 0x7ff ^ SYS_execve /* 0xdd */
    xori a7, a7, 0x7ff
    ecall
>>> print(pwnlib.shellcraft.riscv64.linux.syscall().rstrip())
    /* call syscall() */
    ecall
>>> print(pwnlib.shellcraft.riscv64.linux.syscall('a7', 'a0', 'a1').rstrip())
    /* call syscall('a7', 'a0', 'a1') */
    /* setregs noop */
    ecall
>>> print(pwnlib.shellcraft.riscv64.linux.syscall('a3', None, None, 1).rstrip())
    /* call syscall('a3', ?, ?, 1) */
    sltiu a2, zero, 0x7ff | 1
    sra a7, a3, zero
    ecall
>>> print(pwnlib.shellcraft.riscv64.linux.syscall(
...               'SYS_mmap', 0, 0x1000,
...               'PROT_READ | PROT_WRITE | PROT_EXEC',
...               'MAP_PRIVATE',
...               -1, 0).rstrip())
    /* call mmap(0, 0x1000, 'PROT_READ | PROT_WRITE | PROT_EXEC', 'MAP_PRIVATE', -1, 0) */
    xor a0, t6, t6
    li a1, 0x1000
    xori a2, zero, 0x7ff ^ (PROT_READ | PROT_WRITE | PROT_EXEC) /* 7 */
    xori a2, a2, 0x7ff
    xori a3, zero, 0x7ff ^ MAP_PRIVATE /* 2 */
    xori a3, a3, 0x7ff
    xori a4, zero, -1
    xor a5, t6, t6
    xori a7, zero, 0x7ff ^ SYS_mmap /* 0xde */
    xori a7, a7, 0x7ff
    ecall
>>> print(pwnlib.shellcraft.openat('AT_FDCWD', '/home/pwn/flag').rstrip())
    /* openat(fd='AT_FDCWD', file='/home/pwn/flag', oflag=0) */
    /* push b'/home/pwn/flag\x00' */
    lui t4, 0xfffff & ((0x77702f65 >> 12) + 1)
    xori t4, t4, 0x7ff & 0x77702f65
    addi t4, t4, -0x800
    lui t6, 0xfffff & ((0x6d6f682f >> 12) + 1)
    xori t6, t6, 0x7ff & 0x6d6f682f
    addi t6, t6, -0x800
    slli t4, t4, 0x20
    xor t4, t4, t6
    sd t4, -16(sp)
    lui t4, 0xfffff & (~0x6761 >> 12)
    xori t4, t4, ~0x7ff | 0x6761
    addi t4, t4, -0x800
    lui t6, 0xfffff & ((0x6c662f6e >> 12) + 1)
    xori t6, t6, 0x7ff & 0x6c662f6e
    addi t6, t6, -0x800
    slli t4, t4, 0x20
    xor t4, t4, t6
    sd t4, -8(sp)
    addi sp, sp, -16
    sra a1, sp, zero
    xori a0, zero, AT_FDCWD /* -0x64 */
    xor a2, t6, t6
    /* call openat() */
    xori a7, zero, 0x7ff ^ SYS_openat /* 0x38 */
    xori a7, a7, 0x7ff
    ecall