array(5) { ["chapterid"]=> string(8) "49409218" ["articleid"]=> string(7) "7300050" ["chaptername"]=> string(8) "第25章" ["content"]=> string(3502) "但有了钥匙,还得找到锁。
他卡在最后一步:伪造那张函数表时,需要知道目标函数在内存里的准确位置。他用的是2.31版本文档里记录的位置——偏移量0x88。但exploit运行了五次,每次都崩溃,跳到了一个无效的内存地址。
程序崩溃了,屏幕上跳出一行红色的错误信息:内存访问违规。
地址不对。偏移不对。2.31的文档里找不到2.34的答案。
他的右手一直在动——敲键盘,摸下巴,敲键盘,又摸下巴。左手偶尔摸到手腕上那条粉色的疤,指腹来回蹭两下,又放回键盘上。
八分钟。他盯着那行崩溃信息看了八分钟。
"你卡在哪了?"
林墨的声音从身后传来。赵一鸣没回头——他不喜欢被打断,尤其在堆利用这种每一步都不能错的操作中间。
"函数表的位置偏移。"赵一鸣说,语气带着烦躁。"2.34改了内部结构体的布局,我用的旧偏移对不上。"
"你从内存里直接看过实际的布局吗?"
"还没有。我在用文档里的——"
"文档是2.31的。靶场跑的是2.34。你用旧文档的偏移当然对不上。"林墨的声音很平,像在陈述天气。"先写一段代码把实际内存布局打印出来,然后从里面算偏移。别在文档上浪费时间。"
赵一鸣转过头看他。嘴唇动了一下,没说话。
那个表情林墨见过——不是不服气,是明知道对方说得对但不想承认。赵一鸣在选拔赛上已经被林墨"指点"过一次,现在又在同一个地方被指点第二次。
"我知道要看实际内存。"赵一鸣说。"我正准备做。"
"你已经盯着这个偏移看了八分钟了。"
"我在想FSOP是不是正确的路。也许我应该换——"
"FSOP是对的。你的利用链前半段没有问题,堆重叠和任意地址写都构造得很干净。你只是差最后一步——从实际内存里拿偏移。"
林墨说完,转身回自己的位置了。他没有多留一秒——他知道赵一鸣需要的不是更多的指导,而是空间。一个人在卡题的时候,最烦的不是不知道答案,是有人站在旁边看你不知道答案。
赵一鸣没有马上回答。
他盯着屏幕看了两秒。屏幕上是他写了两个小时的exploit脚本,三百多行Python代码。脚本的前半段很干净——堆重叠的构造、指针劫持、任意地址写,每一步都有注释。卡住的是最后一段:伪造标准输出结构体里的函数表。
林墨让他从实际内存里拿偏移。他照做了——加了一段代码,从目标地址开始读取256字节的内存数据。
数据打印出来的那一刻,偏移一目了然。
他的函数表指针差了`0x1e0`——十六进制的1e0,换算成十进制就是480字节。为什么差480?因为glibc 2.34在标准的函数表之外新增了一个宽字符版本的函数表,多出来的这480字节把后面所有东西的位置都往后推了。就像一栋楼里突然在二楼插了一层,三楼以上的门牌号全得重新排。
修正偏移。exploit第六次运行——成功。
flag出来的那一刻,赵一鸣长出一口气,在桌子上轻轻锤了一拳——跟选拔赛结束时一模一样的动作。手背碰到桌面的声音很闷,矿泉水瓶晃了一下。
但这一次他没有释然。
他转过头来看林墨。
"你是不是每次都在等我卡住,然后告诉我哪里错了?"" ["create_time"]=> string(10) "1785963703" }