iot入门--mips基础
编译MIPS环境
1 | |
运行和调试
qemu 环境搭建
qemu两种模式 qemu-user和qemu-user-static
1 | |
运行程序
小端序:qemu-mipsel ./xxx
大端序:qemu-mips ./xxx
调试
多架构调试工具
1 | |
终端运行
1 | |
再开另一个终端
1 | |
mips相关知识
指令集
路由器是一种嵌入式系统,多采用 MIPS 和 ARM 这两种指令架构
MIPS 指令架构属于 RISC (精简指令集) 体系,是一种普遍应用于小型设备的处理器架构,使用 MIPS 指令架构的 Linux 系统便被称为 MIPS Linux,MIPS 架构广泛应用于嵌入式系统领域
RISC 架构的一些典型指令集包括 MIPS, ARM, RISC-V
在路由器中,常用的一种 MIPS 架构就是 MIPS32
在 MIPS 体系结构中有 32 个通用寄存器 REGISTER,其中主要的寄存器如下
| REGISTER | NAME | USAGE |
|---|---|---|
| $0 | zero | 存储常量 0 |
| $2-$3 | v0−v1 | 存放函数调用的返回值或表达式 |
| $4-$7 | a0−a3 | 作为函数调用的前四个参数 (arguments) |
| $8-$15 | t0−t7 | 供汇编程序使用的临时寄存器 临时变量 |
| $16-$23 | s0−s7 | 调用子函数时 用于保存原寄存器的值 |
| $24-$25 | t8−t9 | 供汇编程序使用的临时寄存器 补充_t_0−t7 |
| $26-$27 | k0−k1 | 中断/异常处理程序使用 保存系统参数 |
| $28 | $gp | 全局指针 (Global Pointer) |
| $29 | $sp | 堆栈指针 指向栈顶 (Stack Pointer) |
| $31 | $ra | 返回地址 (return address) |
然后还有 3 个特殊的寄存器,分别是 PC (程序计数器)、HI (乘除结果高位寄存器)、LO (乘除结果低位寄存器)
MIPS32 架构的寻址模式有寄存器寻址、立即数寻址、寄存器相对寻址和 PC 相对寻址
在 MIPS 指令集中,需要重点关注的是:
- l 开头的 LOAD 加载指令和 s 开头的 STORE 存储指令,用于从存储器中读取数据到寄存器,或者将寄存器中的数据保存在存储器中
- move 指令用于寄存器之间的值传递
- 算术运算指令的操作数只能是寄存器,例如
add, sub, mult, div… 它们与 AMD 架构下的算术运算指令比较大的区别是操作数的使用和数量,MIPS 架构的算数运算结果都会存在另外一个寄存器中,而不是去覆盖某一个原本存储某个操作数的寄存器 - slt 指令类似于 cmp
- syscall 的系统调用号存放在 $v0 中
- 分支跳转指令由 b 开头,如
b target;beq $t0, $t1, target等 - 常见的跳转指令有
j target;jr $t3;jal target
函数调用

传参:
函数调用时传参:如果函数的参数小于等于四个,那么会使用 $a0 ~ $a3 寄存器来存放参数。如果参数多于四个,那么多于的参数则存放到栈里
调用:
MIPS32 架构下的函数有两种类型——叶子函数和非叶子函数。如果一个函数中不会再调用其他任何函数,那么这个函数就是一个叶子函数,其余的函数都是非叶子函数
函数 A 调用函数 B。如果 B 是叶子函数,那么在调用 B 函数时,会将 B 函数的返回地址存入 $ra 寄存器;如果 B 是非叶子函数(B 函数内部调用了一个 C 函数),那么在跳转到 B 函数时,会将其返回地址先存入 $ra 寄存器中,随后在 B 函数内部再将 $ra 寄存器的值存入栈中(位于 fp-0x4 的位置,如下图)。当 B 函数调用 C 函数时,会将其返回地址存入 $ra 寄存器,在返回时执行 jr $ra 指令回到 B 函数。现在假设 B 函数已经执行完毕准备返回到 A 函数,会将原先存入栈里的返回地址读到 $ra 寄存器中,最后执行 jr $ra 指令,回到 A 函数
demo如下
1 | |
传参
叶子函数


非叶子函数


sp + 0x20保存着旧fp地址
sp + 0x24保存着返回地址
栈溢出
对于非叶子函数的话,返回地址保存在栈中,通过栈溢出进行劫持返回地址即可。
对于叶子函数,利用就比较局限。
例子
axb_2019_mips
1 | |
1 | |
vuln中有栈溢出,因为mips中是没有nx的,通过栈迁移来执行shellcode

从这里可以看出,read的第二个参数a1是由fp控制的。同时又有栈溢出

只要我们控制fp,再返回时通过 lw $fp, 0x38+var_s0($sp) 就能够实现任意地址写。同时劫持ra进行第二次读入
因为我们控制了fp为bss段地址 move $sp, $fp 通过这一条指令即可栈迁移到bss段上。
因为第二次读入时都是通过sp偏移来进行寻址的,我们只需要再bss段中设置好地址就能够劫持ra
读入时从sp + 0x18开始读入,通过栈溢出,将sp + 0x38设置返回地址,在sp + 0x40处布置好shellcode就能够执行shellcode来getshell
1 | |
- 标题: iot入门--mips基础
- 作者: heart22
- 创建于 : 2025-10-16 12:49:24
- 更新于 : 2025-10-16 12:50:38
- 链接: https://heart22.top/2025/10/16/iot入门-mips基础/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。