漏洞学习笔记——堆溢出原理

最近在学习堆的溢出原理,但是查了网上和书上的一些讲解,总是感觉缺少一些关键点。所以理解起来总是有点晕,经过努力的调试分析后,总结了下面的更为详细的堆溢出原理。如果不准确的地方,希望大佬可以提醒一哈~

1.堆的结构:

struct _LIST_ENTRY{
	DWORD Flink;
	DWORD Blink;
}
//空闲堆头结构
struct _HEAP_FREE_ENTRY{
	union{
		struct{
			union{
				struct {
					WORD Size;
					BYTE Flags;
					BYTE SmallTagIndex;
				}
				DWORD SubSegmentCode;
			}
			WORD PreviousSize;
			union{
				BYTE SegmentOffset;
				BYTE LFHFlags;
			}
			BYTE UnusedBytes;
		};
		struct{
			union{
				struct {
					WORD FunctionIndex;
					WORD ContextValue;
				};
				DWORD InterceptorValue;
			};
			WORD UnusedBytesLength;
			BYTE EntryOffset;
			BYTE ExtendedBlockSignature;
		};
		struct{
			DWORD Code1;
			WORD  Code2;
			BYTE  Code3;
			BYTE  Code4;
		};
		ULONGLONG AgregateCode;
	};
	_LIST_ENTRY FreeList;
}

//已使用堆的头结构
struct _HEAP_ENTRY{
    //这个结构只比_HEAP_FREE_ENTRY少了一个FreeList;
}
//上面的结构不是百分百正确的,这些都是通过WinDbg调试猜的。

下面这个是winDbg中的数据结构截图。

这两个结构仅仅就差了个FreeList

2.堆溢出原理

当堆溢出发生时,可能会将后面的堆结构全部覆盖掉。而后面的堆有可能是个使用过的_HEAP_ENTRY,也有可能是一个空闲堆_HEAP_FREE_ENTRY。

如果当后面是一个空闲堆时,就可以将_HEAP_FREE_ENTRY最后的FreeList结构覆盖成自己想要的数据。而FreeList是一个_LIST_ENTRY结构。这个结构中有两个成员,分别是Flink和Blink。分别表示的是上一个空闲堆和下一个空闲堆。

那么关键来了,当你调用HeapFree释放刚刚使用的堆时,就会触发一种机制,就是将释放的堆与后面的空闲堆相合并。但此时后面的空闲堆已经被你污染覆盖了。而在合并的过程中,他会修改空闲堆Blink和Flink所指向的空闲堆中的FreeList,以便让前后的空闲堆衔接在一起(因为空闲堆就是一个双向链表,当某一个节点发生改变时,你就要需要把前面的节点指针和后面的节点指针都重新做一遍调整,也就是重新连接双链表节点)。

这个机制就直接导致了堆溢出利用的可能性。因为不管是什么溢出,我们最终的目的都是控制EIP,就是覆盖栈中的返回地址。而到现在,可能还有人没有意识到问题的严重性,那么继续。

假设:需要释放的堆为A,后面被覆盖污染的空闲堆为B。

此时被污染覆盖的空闲堆B中的Flink/Blink已经是我们可以随意修改的地址。那么当释放的堆A和污染空闲堆B进行合并时,会变成一个更大的空闲堆C,那么此时空闲堆C的首地址就会发生改变,所以需要重新连接空闲堆链表。想要重新连接,就需要找到上一个空闲堆,然后并将其中的Blink修改为合并后空闲堆C的首地址。可能已经有人感觉到一丝丝的不寻常了,继续。

因为合并后的空闲堆C中的Flink和Blink是我们可以随意修改的。这就导致上一个空闲堆是我们可以随便指定的。而系统根本不知道我们会指向那里,他依旧会傻傻的去修改所指向地方的Blink。假如此时我们将空闲堆C中的Flink地址覆盖成栈地址。那么他就会把栈当成上一个空闲堆。然后去栈中寻找Blink的位置,并将其修改为空闲堆C的首地址。虽然我们的堆A已经释放了,但里面的数据还在啊,系统可不会勤快的置空呢。而空闲堆C的首地址,其实就是堆A的首地址。因为A和B合并时,其实就是把B叠在了A的屁股后面。

释放了一个有用堆。然后他会和后面的空闲堆合并在一起。而且空闲堆首地址也改变了。

而A中是有我们自己的数据的。这样就可以将栈中的数据覆盖成我们自己的数据,甚至长度算好了也可以覆盖栈中的返回地址。

OK,这就是堆的溢出原理啦。如果有错误的地方,希望大家指正。

 

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
好的,关于 jQuery 的事件,我可以和你分享一些学习笔记。 1. 绑定事件 在 jQuery 中,我们可以通过以下方式来绑定事件: ``` $(selector).event(function(){ // 事件处理程序 }) ``` 其中,`selector` 表示要绑定事件的元素,`event` 表示要绑定的事件类型,比如 `click`、`mouseover` 等等。事件处理程序则是在事件触发时要执行的代码块。 2. 多个事件绑定 我们可以通过 `on()` 方法来同时绑定多个事件: ``` $(selector).on({ event1: function(){ // 事件处理程序1 }, event2: function(){ // 事件处理程序2 } }) ``` 这样,当 `event1` 或 `event2` 中任意一个事件触发时,对应的处理程序都会被执行。 3. 解除事件 如果需要解除某个元素的事件处理程序,可以使用 `off()` 方法: ``` $(selector).off(event); ``` 其中,`event` 表示要解除的事件类型。如果不指定事件类型,则会解除该元素上所有的事件处理程序。 4. 事件委托 在 jQuery 中,我们可以使用事件委托来提高性能。事件委托是指将事件绑定到父元素上,而不是绑定到子元素上,然后通过事件冒泡来判断是哪个子元素触发了该事件。这样,当子元素数量较多时,只需要绑定一次事件,就可以监听到所有子元素的事件。 ``` $(selector).on(event, childSelector, function(){ // 事件处理程序 }) ``` 其中,`selector` 表示父元素,`event` 表示要绑定的事件类型,`childSelector` 表示要委托的子元素的选择器,事件处理程序则是在子元素触发事件时要执行的代码块。 以上是 jQuery 中事件的一些基本操作,希望对你有所帮助。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤月丶星辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值