MIPS32架构堆栈
在MIPS32架构中,每次调用一个函数时,需要将当前调用栈的栈顶指针向下(也就是低地址方向)移动n个比特(也就是减去n个比特),这n个比特的空间就构成了当前被调用函数的栈帧。在这之后栈顶指针便不再移动,只能使用栈顶指针加上或减去一个偏移量来操作栈帧中的变量。最后,在函数返回时将栈顶指针再加上n个比特来恢复调用该函数前的栈现场。
读者可以查看文稿中的两幅图,分别代表了函数A调用函数B之前和函数B正在执行时栈顶指针(SP)的变化情况:
关于这个调用参数空间的概念,比如说,函数A调用函数B,函数A会在自己的函数栈空间中预留一部分空间来保存函数B的参数,这个预留的空间就是调用参数空间。
返回地址(RA寄存器)
对于理解MIPS32架构中的缓冲区溢出原理,还有一个很重要的知识点就是函数的返回地址,在MIPS架构下,假如函数A调用了strcpy函数时,会将调用strcpy函数后需要返回的地址存入RA寄存器。这样当执行完函数strcpy后,跳转指令会从RA寄存器取出返回地址,以便继续执行后续的指令调用。
同样的,在A函数中调用的其他函数(如函数B)也可能基于同样的原因对RA寄存器进行修改,所以,在函数B刚开始运行时,会首先将RA寄存器的值保存到函数B的栈空间中,以便在函数B结束运行时从栈空间中恢复刚刚保存的RA寄存器的值。
同样的,为了防止函数A调用的其他函数对RA寄存器进行修改,在函数A刚开始运行时,会首先将当前的RA寄存器的值保存到函数A的栈空间中,然后在函数A的末尾处将RA寄存器的值进行恢复。
我在文稿中列出了一段C语言代码,和使用mips-linux-gcc编译器对这段代码编译后的反汇编代码,读者可以看图体会一下。对于汇编代码,你可能不太熟悉,我在后面的分享中会涉及,为了便于理解,这里你可以只看红色方框部分的汇编代码注释:
当函数A执行到末尾时,会从栈空间取出刚刚保存的RA地址对RA寄存器进行恢复:

当执行完恢复指令后,RA寄存器的值就变成了刚刚传入的“AAAA”。
今天我们结合示例代码讲解了路由器中缓冲区溢出的原理,在文稿中有一些反汇编代码,你可能对此有些陌生,但对于理解缓冲区溢出的原理并没有什么大的问题。不过,为了后面的ShellCode开发能够顺利进行,我在下次的分享中,将针对MIPS架构的汇编指令进行总结和分享。
最后,希望本次的分享能够给你带来帮助,谢谢大家。
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!