我试图理解经典的缓冲区溢出漏洞,其中输入缓冲区会覆盖堆栈,函数返回地址将保存在堆栈和上层内存区域(通常将shell代码放在此处)中。互联网上有很多这样的例子,我想我对此非常了解:
您将更多数据放入开发人员已确定大小的某些输入缓冲区中
您的输入将覆盖函数参数和堆栈上调用函数的返回地址
当操作系统尝试从发生溢出的功能返回时,该地址已加载到EIP中,这就是使您可以将控制的数据获取到EIP寄存器中的原因(当不仔细阅读某些文章时,您会感觉可以覆盖CPU寄存器)当然不是这种情况,您只能覆盖堆栈,但CPU会将堆栈中的地址加载到其寄存器中)
如果漏洞利用程序设计合理,则加载到EIP中的值将使程序跳至Shell代码的开头(请参见第5点)
我想我已经了解的下一件事是“ JMP ESP”机制。在实验室环境中复制崩溃时,您会在内存中寻找一个包含“ JMP ESP”指令的位置,然后用该地址覆盖EIP(现在我的措词不准确,我知道...)。至少对于相同的OS版本,无论您多长时间运行一次,什么时间运行,哪个线程在执行您的东西等,该地址都必须相同。该地址不得包含任何禁止的字节。代码将跳转到该地址(同时堆栈减少4个字节),因此“ jmp esp”将跳转到溢出缓冲区中下一个我将其值覆盖为EIP的位置之后的地址。通常是shellcode所在的地方,可能以NOP开头。
现在出现了问题。
到目前为止,我读过的所有文章都在DLL中寻找“ JMP ESP”指令的地址(该地址不能重定位,不能用ASLR编译,等等)。为什么不在exe本身中寻找“ jmp esp”呢?为什么它需要在DLL中?
我已经在Immunity Debugger中运行了“!mona modules”命令,并且显示的满足所有这些条件的唯一模块是exe本身。当我查看流行的漏洞利用数据库时,该地址始终位于已加载的DLL中。
我看不出有任何明显的原因。exe也可以以与DLL相同的方式位于内存中的相同地址。有什么不同?