此题是LCTF 2016年的pwn100
参考文章:https://bbs.ichunqiu.com/forum.php?mod=viewthread&tid=42933&ctid=157
0x01 文件分析
- 64位elf
- 无stack
- 无PIE
0x02 运行分析
看起来像一个无限循环,不断接收输入。
0x03 静态分析
main:
sub_40068E:
sub_40063D:
整个程序由3个嵌套的程序组成,我们可以看到sub_40063D是主要的程序,接受单个字符并存储到传入的参数a1所指向的空间之内,同时分析sub_40068E发现sub_40063D中a1就是sub_40068E中的v1,并且v1的栈空间大小就只有0x40,而sub_40063D接受的输入量有0x200个字节,这样就存在栈溢出漏洞了。
通过查找字符串和函数,没有发现可以用来直接ROP的函数,并且没有libc的信息。走到这一步就遇到了难点。
之后,通过分析函数列表,里面有puts这个库函数,联系pwntools中的DynELF,我们可以将libc的地址泄露出来,再来构造ROP。
0x04 思路分析
没有libc和可利用后门,但不代表程序就是不能攻破的,在这里需要注意的是x86和x64的函数调用传递参数的方式是不一样的,我就是在这个地方卡了许久。
x86中,函数调用是直接将参数压栈,需要用的时候直接将参数放在栈上,调用的函数就能直接取得参数并运算。如图:
调用read函数的时候,参数直接放入栈中,但是x64的程序不一样,x64的gcc优化了x86的传参方式,x64程序设立了几个寄存器李存放参数,调用函数的时候先向寄存器之中放参数,当参数的数量大于寄存器的时候,才会向栈中放参数。
这是本题中的sub_40068E函数,可以看到其参数是放在rdi和esi两个寄存器之中的,这就是两种结构的不一样,如果要在x64的程序之中构造rop,我们就必须向寄存器存放参数。
举个例子:
fun(1,2,3,4,5,6,7,8,9