堆溢出DWORD SHOOT原理

1、双向链表上有a、b、c一共3个连续的堆块,a、b、c三者之间的实际物理地址可能相差很大,但是绝对不会三者之间无其他字节,如果无其他字节,那表示他们三个可以合并成一个物理连接起来的大块,堆管理系统很快会让他们三者搞基成一个大个子堆块,拆下来重新按照其尺寸重新链接到该去的链表位置去。。。而不会放纵其在链表上物理地址紧密链接的同时还分成3个堆块串联在链表上。

2、返回正题,拆下其中一个堆块b时,会产生a、c之间的空缺,导致a、c无法相互知晓。所以堆管理系统会在拆b时,把a和c缝缝补补,连在一起,成为新链表,等待下次拆分、合并等等。

  关键来了,以b堆块为例

  【1】每个堆块前边8字节是堆块首部内存 第9~12字节保存他前方堆块的块数据地址. 也就是a的块数据地址

                这个指针叫做前向指针

  【2】每个堆块都在 第13~16字节处保存他后面那个堆块的块数据地址 也就是c的块数据地址 这个指针叫做后向指针

       【3】当用到堆块操作时 会执行 mov [13~16], 9~12 当再次调用分配函数时会执行后向指针中的代码

  以此类推每2个相邻堆块之间由于双向可循,由于每个堆块上都记载着往该块左边或右边方向走的下一个地址(即上述9~12、13~16字节数据均为地址值),所以断掉一个块(暂称为块b)时,该断掉的块的左右两边欲形成新连接,必须知道彼此的地址。这个重新知晓相互地址的任务由即将被拆下来的堆块去处理,因为它才同时熟悉两边的邻居,知道他们地址,于是该堆块(又叫节点)把他身上距离头顶第9~12字节的4个字节的数据(实际上是他右邻居堆块的门牌号地址,举例0x001A0038)抄下来,给到左邻居。怎么给?在他身上距离头顶第13~16字节处的4个字节,就是他左邻居的门牌号地址(这个数据肯定比他右邻居的门牌号地址小,假设0x001A000A),我们于是按照这个左邻居地址,在堆管理系统帮助下,把0x001A0038这个数值给到左邻居家去:mov [0x001A000A],0x001A0038    。。。。都知道[]方括号的意思吧。等右邻居的地址给了左邻居后,再把左邻居的地址按此方法给到右邻居,他此时也就从链表上断下来了,因为空表链表上已经没有他存在的痕迹了。

  而这个断掉块b过程之前,我们先通过字符串变量溢出,将字符串从其他块溢出到块b中,即覆盖了他的第9~16字节数据,效果就是改了他身上所保管的左、右邻居门牌号地址,一般就是右邻门牌号覆盖为shellcode入口地址,左邻门牌号覆盖为各种特殊地址,比如重要函数调用地址,栈帧中函数返回地址,栈帧中SEH的句柄。这样,在块b断下来时,他会把shellcode地址赋值到某个经常调用的函数的地址上,或栈帧中当前函数返回地址上,或栈帧中距离当前栈最近的SEH异常处理最近的那个句柄。

  然后堆块这边就没他们什么事了,就等着某个函数被调用,错误跳转到shellcode地址去执行我们构造的code;等着栈帧中当前函数返回时执行的却是跳转到shellcode地址去执行我们构造的code;溢出发生了导致系统启动异常处理,执行了SEH异常处理相关函数,跳转到shellcode地址去执行我们构造的code。。。。。。

  溢出并恶意执行了我们的代码。

  现在回头去看,堆块断下来时,把错误的右邻居门牌号(子弹,shellcode入口地址,共计4个字节,即为DWORD双字),抄给左邻居时(左邻居的地址已经被改为目标地址,任何能被调用的地址),就是发生了子弹射击,DWORD Shoot是也。

   至于后面的把左邻居地址给右邻居地址的操作,会发生指针反射现象,会改写shellcode的5到8的4字节,大多数情况不会发生问题,解决方案就是把shellcode第一条指令修改为jmp 跳过到第九字节的地址 具体如图:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值