为啥栈迁移使用教程

极客

为啥栈迁移使用教程?别急,这篇干货让你秒懂底层逻辑!

哎,兄弟们,姐妹们,搞技术的各位老铁,今儿咱们不聊那些虚头巴脑的框架,也不扯那些花里胡哨的“AI生成神文”,咱们就踏踏实实坐下来,聊聊那个让无数新手挠头、让老手直呼“真香”的栈迁移

为啥栈迁移使用教程

说真的,我刚开始接触这个概念的时候,心里就俩字——为啥?为啥好好的栈指针非要挪个窝?为啥我明明调通了函数,一用栈迁移就崩得亲妈都不认识?直到后来把那层窗户纸捅破,我才恍然大悟,原来这玩意儿不是炫技,是真·救命稻草啊!

先别急着敲代码,咱得先弄明白:啥是栈迁移?

打个比方啊,你玩一个限时闯关游戏,角色当前所在的存档点(栈空间)马上就要塌方了(溢出/不够用),但前方还有一大片地图(逻辑代码)要走,这时候,系统告诉你:小伙子,旁边那块空地(另一个可控内存区域)够大,你赶紧把游戏进度(返回地址、局部变量)挪过去继续玩!——这就是栈迁移

说白了,就是当原本的栈帧(比如栈顶被压得太低,或者栈地址被某种原因锁死不能用)不舒服、不配继续运行下去时,咱用 leave; ret 或者 pop esp 这类神仙操作,强行把 esp 指向我们精心伪造的一片内存上,让程序顺着我们铺好的路接着跑,哎,您还甭说,这招在 CTF(夺旗赛)和漏洞利用里,简直是屠龙刀

为啥非要费劲吧啦学这个?图啥呀?

第一,那是为了“偷”输入空间啊! 你想啊,一般函数接收输入,要么在栈上,要么在某个固定缓冲区里,如果溢出字节数不够咋办?比方说,只能溢出8个字节,你就想把后门函数地址给覆盖完整?那简直是痴人说梦!这时候,栈迁移就拍着胸脯站出来了:“别慌,我只要控制 EBP,一次 leave; ret 就能带飞你!” 咱把栈指针挪到一个我们有大量控制权的 .bss 段或者堆上,诶,那你想布置多长的 ROP 链(返回导向编程)都随你便!这不比在窄胡同里开车舒服多了?

第二,应对“不可预测”的环境。 有时候开启 PIE(位置无关可执行)或者地址随机化,你压根不知道当前栈的真实地址是多少,但你手里有一个已知的、能写大量数据的地方,那你直接把 esp 干到那去,逻辑不就全活了?这感觉就相当于,在一片漆黑的迷宫里,你手里突然拿到了一盏固定的探照灯(固定地址),那还不横着走?简直美滋滋!

光说不练假把式,到底咋迁移啊?(附送灵魂笔记)

说到这里,估计兄弟你要问:那具体咋整啊? 来来来,收起瓜子,看黑板!

核心三板斧:劫持 esp -> 伪造栈帧 -> 精准着陆(ret)

你得有个溢出点,假设,程序里有个明显的栈溢出,但空间极小(就够挤进去一个返回地址的),这时候,我们就在那头像里找到一条 leave; ret 的指令(这玩意儿简直是栈迁移的千层饼套路),第一波溢出,我们把 EBP 覆盖成我们想要的新栈地址(bss 段 + 偏移),然后返回地址指向 leave_ret。

嘿,神迹发生了! 执行第一个 leave 时,CPU 会把旧 EBP 弹到 ESP,RET 就把我们的新地址弹给 EBP 了,紧接着第二个 leave,ESP 直接跟上新 EBP,再 RET 就直接从我们伪造的栈顶取地址执行了!这不就顺杆子爬过去了嘛! 全程只需要控制两次返回地址,不需要你塞满几千个垃圾字符,这事儿办得漂亮吧?!

但也别高兴太早,血泪教训来了! 兄弟我提醒一句:伪造的新栈区一定要可写! 你非得把栈迁移到代码段 .text 上,那等着你的就是妥妥的 Segmentation Fault,白忙活一场,还有就是,注意堆栈平衡!新栈上每一个 ROP 链的排列顺序,你得跟个精致的老裁缝一样,一针一线都缝对了,错一个字节整个链条全崩。

这玩意儿值不值得啃?

依我看,太值得了! 只要你想深入PWN(漏洞利用)领域,想跟那些高难度的保护机制掰掰手腕,栈迁移就是那把绕过后门锁的“万能钥匙”。

哎呦,写到这儿我都热血沸腾了,回想起当年为了调试一个栈迁移的题目,愣是盯着 GDB(调试器)看了一下午,看着那 esp 指针像是调皮的孩子一样跳来跳去,最后成功弹到 shell 那一瞬间,感觉整个世界都亮了!那种感觉,怎么说呢?比夏天灌一瓶冰可乐还爽!

所以啊,别嫌难,也别问 为啥栈迁移使用教程 这么麻烦,因为真正的技术,永远藏在这些“拐个弯”的智慧里,好啦,篇幅有限,今天先抛砖引玉,老铁们如果觉得有收获,或者有别的疑惑,欢迎在评论区随时扔板砖过来,我保证用栈迁移的姿势接住它!

那咱们,下篇文见!去练题咯!🚀


本文为栈迁移学习心得感悟,高手轻喷,新手记得多调试几遍,记住那句口诀——"栈不够,迁移凑,ROP 天下走"!

文章版权声明:除非注明,否则均为极客网安-咸鱼原创文章,转载或复制请以超链接形式并注明出处。

目录[+]