Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions examples/shellcode_mips64_run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#

import sys

sys.path.append("..")
from qiling import Qiling
from qiling.const import QL_ARCH, QL_OS, QL_ENDIAN, QL_VERBOSE

# MIPS64 n64 shellcode: write(1, "MIPS64 hello\n", 13) then exit_group(0).
#
# it uses the n64 syscall numbers (write=5001, exit_group=5205) and computes the
# address of the message with a bal/daddiu pc-relative trick. assembled with
# binutils mips64-linux-gnuabi64-as:
#
# .set noreorder
# __start:
# li $v0, 5001 # __NR_write
# li $a0, 1 # fd = stdout
# bal load
# nop
# load:
# daddiu $a1, $ra, (msg - load) # a1 = &msg
# li $a2, 13 # len
# syscall
# li $v0, 5205 # __NR_exit_group
# li $a0, 0
# syscall
# msg:
# .ascii "MIPS64 hello\n"
MIPS64EB_LIN = bytes.fromhex('''
2402138924040001041100010000000067e500182406000d0000000c24021455
240400000000000c4d49505336342068656c6c6f0a
''')

# little-endian counterpart of MIPS64EB_LIN: the instruction words are
# byte-swapped while the trailing string is left as-is
MIPS64EL_LIN = bytes.fromhex('''
891302240100042401001104000000001800e5670d0006240c00000055140224
000004240c0000004d49505336342068656c6c6f0a
''')


if __name__ == "__main__":
print("\nLinux MIPS 64bit EB (big-endian) Shellcode")
ql = Qiling(code=MIPS64EB_LIN, archtype=QL_ARCH.MIPS64, ostype=QL_OS.LINUX, endian=QL_ENDIAN.EB, verbose=QL_VERBOSE.DEFAULT)
ql.run()

print("\nLinux MIPS 64bit EL (little-endian) Shellcode")
ql = Qiling(code=MIPS64EL_LIN, archtype=QL_ARCH.MIPS64, ostype=QL_OS.LINUX, endian=QL_ENDIAN.EL, verbose=QL_VERBOSE.DEFAULT)
ql.run()
72 changes: 72 additions & 0 deletions qiling/arch/mips64.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python3
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#

from functools import cached_property
from typing import Optional

from unicorn import Uc, UC_ARCH_MIPS, UC_MODE_MIPS64, UC_MODE_BIG_ENDIAN, UC_MODE_LITTLE_ENDIAN
from capstone import Cs, CS_ARCH_MIPS, CS_MODE_MIPS64, CS_MODE_BIG_ENDIAN, CS_MODE_LITTLE_ENDIAN
from keystone import Ks, KS_ARCH_MIPS, KS_MODE_MIPS64, KS_MODE_BIG_ENDIAN, KS_MODE_LITTLE_ENDIAN

from qiling import Qiling
from qiling.arch.arch import QlArch
from qiling.arch import mips_const
from qiling.arch.models import MIPS_CPU_MODEL
from qiling.arch.register import QlRegisterManager
from qiling.const import QL_ARCH, QL_ENDIAN


class QlArchMIPS64(QlArch):
type = QL_ARCH.MIPS64
bits = 64

def __init__(self, ql: Qiling, *, cputype: Optional[MIPS_CPU_MODEL], endian: QL_ENDIAN):
super().__init__(ql, cputype=cputype)

self._init_endian = endian

@cached_property
def uc(self) -> Uc:
endian = {
QL_ENDIAN.EB: UC_MODE_BIG_ENDIAN,
QL_ENDIAN.EL: UC_MODE_LITTLE_ENDIAN
}[self.endian]

return Uc(UC_ARCH_MIPS, UC_MODE_MIPS64 + endian)

@cached_property
def regs(self) -> QlRegisterManager:
# the register names are shared with MIPS32; unicorn widens them to
# 64 bits under UC_MODE_MIPS64
regs_map = dict(
**mips_const.reg_map
)

pc_reg = 'pc'
sp_reg = 'sp'

return QlRegisterManager(self.uc, regs_map, pc_reg, sp_reg)

@cached_property
def disassembler(self) -> Cs:
endian = {
QL_ENDIAN.EL: CS_MODE_LITTLE_ENDIAN,
QL_ENDIAN.EB: CS_MODE_BIG_ENDIAN
}[self.endian]

return Cs(CS_ARCH_MIPS, CS_MODE_MIPS64 + endian)

@cached_property
def assembler(self) -> Ks:
endian = {
QL_ENDIAN.EL: KS_MODE_LITTLE_ENDIAN,
QL_ENDIAN.EB: KS_MODE_BIG_ENDIAN
}[self.endian]

return Ks(KS_ARCH_MIPS, KS_MODE_MIPS64 + endian)

@property
def endian(self) -> QL_ENDIAN:
return self._init_endian
3 changes: 2 additions & 1 deletion qiling/arch/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from functools import lru_cache

from keystone import (Ks, KS_ARCH_ARM, KS_ARCH_ARM64, KS_ARCH_MIPS, KS_ARCH_X86, KS_ARCH_PPC,
KS_MODE_ARM, KS_MODE_THUMB, KS_MODE_MIPS32, KS_MODE_PPC32, KS_MODE_16, KS_MODE_32, KS_MODE_64,
KS_MODE_ARM, KS_MODE_THUMB, KS_MODE_MIPS32, KS_MODE_MIPS64, KS_MODE_PPC32, KS_MODE_16, KS_MODE_32, KS_MODE_64,
KS_MODE_LITTLE_ENDIAN, KS_MODE_BIG_ENDIAN)

from qiling import Qiling
Expand Down Expand Up @@ -126,6 +126,7 @@ def assembler(arch: QL_ARCH, endianness: QL_ENDIAN, is_thumb: bool) -> Ks:
QL_ARCH.ARM: (KS_ARCH_ARM, KS_MODE_ARM + endian + thumb),
QL_ARCH.ARM64: (KS_ARCH_ARM64, KS_MODE_ARM),
QL_ARCH.MIPS: (KS_ARCH_MIPS, KS_MODE_MIPS32 + endian),
QL_ARCH.MIPS64: (KS_ARCH_MIPS, KS_MODE_MIPS64 + endian),
QL_ARCH.A8086: (KS_ARCH_X86, KS_MODE_16),
QL_ARCH.X86: (KS_ARCH_X86, KS_MODE_32),
QL_ARCH.X8664: (KS_ARCH_X86, KS_MODE_64),
Expand Down
16 changes: 15 additions & 1 deletion qiling/cc/mips.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework

from unicorn.mips_const import UC_MIPS_REG_V0, UC_MIPS_REG_A0, UC_MIPS_REG_A1, UC_MIPS_REG_A2, UC_MIPS_REG_A3
from unicorn.mips_const import (
UC_MIPS_REG_V0, UC_MIPS_REG_A0, UC_MIPS_REG_A1, UC_MIPS_REG_A2, UC_MIPS_REG_A3,
UC_MIPS_REG_T0, UC_MIPS_REG_T1, UC_MIPS_REG_T2, UC_MIPS_REG_T3
)

from qiling.cc import QlCommonBaseCC, make_arg_list

Expand All @@ -25,3 +28,14 @@ def getNumSlots(argbits: int):
def unwind(self, nslots: int) -> int:
# TODO: stack frame unwiding?
return self.arch.regs.ra


class mips64n64(mipso32):
# n64 passes the first 8 arguments in registers: a0-a3 followed by a4-a7,
# which are the physical registers $8-$11 (unicorn names them t0-t3). unlike
# o32, n64 reserves no shadow space on the stack.
_argregs = make_arg_list(
UC_MIPS_REG_A0, UC_MIPS_REG_A1, UC_MIPS_REG_A2, UC_MIPS_REG_A3,
UC_MIPS_REG_T0, UC_MIPS_REG_T1, UC_MIPS_REG_T2, UC_MIPS_REG_T3
)
_shadow = 0
1 change: 1 addition & 0 deletions qiling/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class QL_ARCH(IntEnum):
RISCV = 110
RISCV64 = 111
PPC = 112
MIPS64 = 113


class QL_OS(IntEnum):
Expand Down
2 changes: 1 addition & 1 deletion qiling/loader/elf.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ def __push_str(top: int, s: str) -> int:
sp_align = self.ql.arch.pointersize

# mips requires doubleword alignment
if self.ql.arch.type is QL_ARCH.MIPS:
if self.ql.arch.type in (QL_ARCH.MIPS, QL_ARCH.MIPS64):
sp_align *= 2

new_stack = self.ql.mem.align(new_stack - len(elf_table), sp_align)
Expand Down
1 change: 1 addition & 0 deletions qiling/os/blob/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def __init__(self, ql: Qiling):
QL_ARCH.ARM : arm.aarch32,
QL_ARCH.ARM64 : arm.aarch64,
QL_ARCH.MIPS : mips.mipso32,
QL_ARCH.MIPS64 : mips.mips64n64,
QL_ARCH.RISCV : riscv.riscv,
QL_ARCH.RISCV64 : riscv.riscv,
QL_ARCH.PPC : ppc.ppc,
Expand Down
5 changes: 3 additions & 2 deletions qiling/os/linux/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def __init__(self, ql: Qiling):
QL_ARCH.ARM : arm.aarch32,
QL_ARCH.ARM64 : arm.aarch64,
QL_ARCH.MIPS : mips.mipso32,
QL_ARCH.MIPS64 : mips.mips64n64,
QL_ARCH.RISCV : riscv.riscv,
QL_ARCH.RISCV64 : riscv.riscv,
QL_ARCH.PPC : ppc.ppc,
Expand Down Expand Up @@ -64,8 +65,8 @@ def load(self):
'get_tls': 0xffff0fe0
})

# MIPS32
elif self.ql.arch.type == QL_ARCH.MIPS:
# MIPS32 / MIPS64 (same syscall exception number)
elif self.ql.arch.type in (QL_ARCH.MIPS, QL_ARCH.MIPS64):
self.ql.hook_intno(self.hook_syscall, 17)
self.thread_class = thread.QlLinuxMIPS32Thread

Expand Down
Loading