堆溢出 对空表的调试

代码

#include <windows.h>
int main()
{
	HLOCAL h1,h2,h3,h4,h5,h6;
	HANDLE hp;
	hp = HeapCreate(0,0x1000,0x10000);//创建一个新的堆
	_asm int 3//中断,进入OD调试

	h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,3);
	h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,5);
	h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,6);
	h4 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
	h5 = HeapAlloc(hp,HEAP_ZERO_MEMORY,19);
	h6 = HeapAlloc(hp,HEAP_ZERO_MEMORY,24);
	_asm int 3
	
	HeapFree(hp,0,h1);
	HeapFree(hp,0,h3);
	HeapFree(hp,0,h5);
	_asm int 3
	HeapFree(hp,0,h4);
	_asm int 3

	return 0;
}

实验目的

简单理解空表

实验准备

环境:windows xp
编译器:vc++
调试器:OD

实验过程

1.把OD设成默认调试器,打开这段程序触发异常正好卡在HeapCreate后面,这时候的正好把新建好的堆的地址传入eax。
在这里插入图片描述
试了下Heap_Vis这个插件,好像不是那么好用,我用了下,直接给我卡死了,最后还是靠Ctrl+Alt+Del才救回来的(有可能是插件冲突了?懒得去搞了

在这里插入图片描述
2.找到堆的地址发现堆的结构前面先是一段段表。中间是虚分配表,因为堆才初始化,没有虚分配记录所以全都为NULL,然后就是32位的bitmap应该是来统计堆表的分配,如果表被占用则,该对应的bit位上为1.
然后接下来就是空表索引区,但是由于都没有被占用,所有的空表都指向自己的位置。
其中零号空表(0x003a0178)指向的是尾块。

在这里插入图片描述
PS:堆表表头的结构为

ByteName
1~2Self Size 自身的长度
3~4Previous chunk size 上一节的长度
5Segment Index 段索引
6Flags 该位为1的时候,表示该表被占用了
7Unused bytes
8Tag index
9~bFlink in freelist (占用态)
c~fBlink in freelist (占用态)

3.观察到零号空表指向的尾块表头,表头下面的就是指向零号空表的双向链表。实际上这个堆块开始于 0x0030680,一般引用堆块的指针都会跃过 8 字节的块首,直接指向数据区。Self Size为0x130,因为堆中一个单位对应的都是八个字节,所以总空间为 0x130 * 8。

(1)堆块的大小包括了块首在内,即如果请求 32 字节,实际会分配的堆块为 40 字节:8字节块首+32 字节块身。
(2)堆块的单位是 8 字节,不足 8 字节的部分按 8 字节分配。
(3)初始状态下,快表和空表都为空,不存在精确分配。请求将使用“次优块”进行分配。这个“次优块”就是位于偏移 0x0680 处的尾块。
(4)由于次优分配的发生,分配函数会陆续从尾块中切走一些小块,并修改尾块块首中的size 信息,最后把 freelist[0]指向新的尾块位置。
在这里插入图片描述

3.把断点的位置移到HeapAlloc的后面观察每个空间的申请。
0x003a0680到0x003a06e0就是1到6号申请的空间。
开头是02,则代表分配了2 * 8个字节的空间。
开头是04,则代表分配了4 * 8个字节的空间。
然后这个时候再看尾块的表头的Self Size为0x120,因为前面分配了0x10的空间(2 * 4 + 4 * 2 = 0x10)
这时零表中指向尾块的指针也变成了0x003a0700
在这里插入图片描述

4.把断点的位置移到HeapFree h5的后面,观察h1和h3链入了Freelist[2],h5链入了Freelist[4],同时观察Flag位都变为了0,意味着恢复成了空闲态。

在这里插入图片描述

5.又把断点的位置移到HeapFree之后观察堆表h1链入了Freelist[2],h3脱离了Freelist[2]与h1组成的链表链入了Freelist[8],同时观察h3开头的02已经变成了08,此时已经完成了h3,h4,h5的合并。h5也从Freelist[4]中取下了。
堆块合并的过程。堆块合并可以更加有效地利用内存,但往往需要修改多处指针。因此,堆块合并只发生在空表中。在强调分配效率的快表中,堆块合并一般会被禁止(通过设置堆块为占用态)。另外,空表中的第一个块不会向前合并,最后一个块不会向后合并。
Freelist中指向的地址都自动跳过了堆块头的,也就是跳过了那8个字节。

在这里插入图片描述

观察此时Freelist[4]已经变为指向自身,Freelist[2]也只链入了一个h1
在这里插入图片描述

PS:调试堆好像不能用OD直接载入,必须的在进程中调试,不然堆的位置就会出现乱码。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值