mips架构栈溢出
MIPS汇编基础
寄存器:
mips体系结构中有32个通用寄存器,在汇编程序中可以用编号$0~$31表示,也可以用寄存器的名字表示。
mips32架构中定义了3个特殊的寄存器,分别是PC(程序计数器)、HI(乘除结果高位寄存器)和LO(乘除结果低位寄存器)。HI保存乘法的结果的高32位和除法的余数,LO保存低32位和商。
mips的特点:
- mips指令集固定4字节长度,并且必须4字节对齐
- 优先操作寄存器
- mips属于大端序
配置好交叉编译环境之后:
通过mipsel-linux-gcc
来编译程序
qemu使用MIPS程序共有两种方法:
qemu-mips
大端格式qemu-mipsel
小端格式
指令集:
LOAD/STORE指令
- LA(Load Address)指令用于将一个地址或者标签存入寄存器。
基本格式la $rd,addr
,下面的基本一样
- LI(Load Immediate)指令用于将一个立即数存入寄存器
- LW(Load Word)指令用于从一个指定的地址加载一个word类型的值到一个寄存器
- SW(Store Word)用于将一个源寄存器的值存入指定地址
MOVE用于寄存器之间值的传递
mips32架构栈
- mips32函数调用与x86没有太大差别,mips32中没有EBP,进入函数将栈指针向下移动n比特,这个大小为n比特的存储空间就是此函数的stack frame的存储区域。此后栈指针不再移动,只能在函数返回时将栈指针加上这个偏移量恢复。由于不能随便移动栈指针,所以寄存器压栈和出栈的时候必须指定偏移量。
- 调用:函数A调用函数B,函数A会在自己的栈顶留下一部分空间来保存函数B的参数,我们称之为调用参数空间。
- 参数传递方式:前4个传入的参数通过$a0~$a3传递,超过4个放入调用参数空间。
- 返回地址:mips32会把函数的返回地址存入$RA寄存器中。
如果MIPS32架构下函数A不再调用其他任何函数,那么当前函数A就是一个叶子函数,否则函数A就是一个非叶子函数。
函数调用过程:
- 在函数A调用函数B时,首先复制当前的$PC寄存器的值到$RA寄存器,即返回地址。然后跳转到函数B执行。
- 如果函数B是个非叶子函数,函数B首先会把函数A的返回地址存入栈,否则仍然保存在$RA。
- 返回时,如果函数B是个叶子函数,则直接
jr $RA
返回;否则函数B会先从栈中取出地址,然后存入$RA,再使用jr $RA
返回。
工具
gdb-multiarch
多架构的gdb调试工具
set architecture mips
设置架构为mips
set endian little
设置小端序
qemu-mipsel -g 1234 vuln_system
启动qemu远程调试
target remote 127.0.0.1:1234
远程调试
mips-linux-gcc vuln_system.c -static -o vuln_system
编译
利用
源文件
1 | #include <stdio.h> |
分析程序
用cyclic计算偏移放到passwd文件里
返回地址ra和buf的距离是0x4 - (-0x1A0)=0x19C
使用ida的插件mipsrop找到gadget
do_system只需要使用第二个参数,所以我们仅仅修改a1就能调用
0x3C是var_40-var_4得到的
1 | from pwn import * |
拿到shell
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Kazamaycのblog!