堆溢出
今天上午终于把堆溢出看懂了~
一、windows下的堆
堆表:在堆的起始位置,用于索引堆块,分为空闲双向链表Freelist和快速单向链表Lookaside。
空表:128条,free[0]对应大于1024byte的堆块,其余free[i]为8*i大小的堆块。
堆块:前8个字节包含堆块的一些基本信息包括大小等,后面如果是空闲堆块还需要8个字节记录链表的前后地址。
二、堆表的操作
1.分配
选择合适大小的堆块分配 并找零,修改堆块状态值,从堆表中卸下,将地址返回堆申请者;修改双向链表。
2.释放
将堆状态改为空闲态,加入合适的双向链表。
3.合并
相邻的空闲表需要合并,修改堆块大小,修改双向链表。
三、DWORD SHOOT
双向链表操作时,会发生前向指针与后向指针的迁移,如果利用非法数据覆盖指针就会发生DWORD SHOOT。
具体操作可能会出现类似:
node->blink->flink=node->flink;
node->flink->blink=node->blink;
的语句,此时可以劫持进程。
四、P.E.B中的RtlEnterCriticalSection的利用
进程退出时会执行ExitProcess(),进而调用RtlEnterCriticalSection和RtlLeaveCriticalSection函数,如果将RtlEnterCriticalSection地址修改为shellcode地址,则可以劫持进程。
而恰恰我们可以利用双向链表的操作做到这一点,只要合适的堆溢出改变blink和flink分别为shellcode和RtlEnterCriticalSection的地址。
通过上面步骤,当进程执行ExitProcess()时就会进入我们事先布置好的shellcode中去。
补充:
不同操作系统对应的堆地址是不同的,可以通过ollydbg的M查看内存镜像,也可以通过查看每次成功分配堆地址后的EAX寄存器的值。