很显然,我们的脚本出现了问题。我们直接把断点下载main函数的retn处,跟进到ShellCode看看发生了什么:
从这四张图和ShellCode的内容我们可以看出,由于ShellCode执行过程中的push,最后一部分会在执行完push rdi之后被覆盖从而导致ShellCode失效。因此我们要选一个更短的ShellCode,或者就对其进行改造。鉴于ShellCode不好找,我们还是选择改造。
首先我们会发现在ShellCode执行过程中只有返回地址和上面的24个字节会被push进栈的寄存器值修改,而栈溢出最多可以向栈中写0x40=64个字节。结合对这个题目的分析可知在返回地址之后还有16个字节的空间可写。根据这四张图显示出来的结果,push rdi执行后下一条指令就会被修改,因此我们可以考虑把ShellCode在push rax和push rdi之间分拆成两段,此时push rdi之后的ShellCode片段为8个字节,小于16字节,可以容纳。
接下来我们需要考虑怎么把这两段代码连在一起执行。我们知道,可以打破汇编代码执行的连续性的指令就那么几种,call,ret和跳转。前两条指令都会影响到寄存器和栈的状态,因此我们只能选择使用跳转中的无条件跳转jmp,我们可以去查阅前面提到过的Intel开发者手册或其他资料找到jmp对应的字节码,不过幸运的是这个程序中就带了一条。