堆溢出 对HeapFree函数的详细调试

本文通过详细的代码示例和步骤解析,深入探讨了Windows环境下内存分配与释放的过程,特别是使用HeapAlloc函数时堆内存的分配、合并等操作细节。

代码

#include <windows.h>
int main()
{
	HLOCAL h1,h2,h3,h4,h5,h6;
	HANDLE hp;
	hp = HeapCreate(0,0x1000,0x10000);

	
	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);


	return 0;
}

实验目的

了解HeapAlloc函数的操作过程

实验准备

环境:windows 2k professional
编译器:vc++
调试器:OD

实验过程

1.首先观察链表是怎么装载进去的

CPU Disasm
Address   Hex dump          Command                                  Comments
77FCC8E6  |.  8066 05 10    AND BYTE PTR DS:[ESI+5],10 //对堆块中Flag位进行更改,使其为占用态

2.然后修改被装载进去堆块的地址,先改被占用堆块的第一项,第二项,再去修改Freelist[1]中的第一项第二项,然后再把可用的总空间加起来放进堆块一开始偏移0x28的地方。

77FCC909  |.  8D46 08       LEA EAX,[ESI+8]
77FCC90C  |.  8918          MOV DWORD PTR DS:[EAX],EBX
77FCC90E  |.  894E 0C       MOV DWORD PTR DS:[ESI+0C],ECX
77FCC911  |.  8901          MOV DWORD PTR DS:[ECX],EAX
77FCC913  |.  8943 04       MOV DWORD PTR DS:[EBX+4],EAX             //把地址进行替换
77FCC916  |.  8B45 D0       MOV EAX,DWORD PTR SS:[EBP-30]    
77FCC919  |.  0147 28       ADD DWORD PTR DS:[EDI+28],EAX              //add last part
77FCC91C  |>  834D FC FF    OR DWORD PTR SS:[EBP-4],FFFFFFFF

3.然后再把int 3断点往下再移一位,观察堆的拆卸,装载这一系列的操作。先开头还是一些准备的传参的工作,上线程锁啊这些的。然后就进入了关键的函数。这是函数的一波传参。

77FCC8CA  |.  6A 00         PUSH 0                                   //Arg4 = 0
77FCC8CC  |.  8D45 D0       LEA EAX,[LOCAL.12]                       
77FCC8CF  |.  50            PUSH EAX                                 //Arg3 = 指向堆栈中存放数组的指针
77FCC8D0  |.  56            PUSH ESI                                 //Arg2 = 指向Free的那个堆块的堆块头部
77FCC8D1  |.  57            PUSH EDI                                 //Arg1 = 指向整个堆块的最前面
77FCC8D2  |.  E8 EA000000   CALL 77FCC9C1                             //ntdll.77FCC9C1

4.然后的代码就是判断上一个堆块的一些数据,来判断要不要合并

77FCC9C1  /$  55            PUSH EBP                                 // ntdll.77FCC9C1(guessed Arg1,Arg2,Arg3,Arg4)
77FCC9C2  |.  8BEC          MOV EBP,ESP
77FCC9C4  |.  53            PUSH EBX
77FCC9C5  |.  56            PUSH ESI
77FCC9C6  |.  8B75 0C       MOV ESI,DWORD PTR SS:[ARG.2]             //指向Free的那个堆块的堆块头部
77FCC9C9  |.  8B5D 08       MOV EBX,DWORD PTR SS:[ARG.1]             //指向HeapCreate堆块的头
77FCC9CC  |.  57            PUSH EDI
77FCC9CD  |.  8BFE          MOV EDI,ESI
77FCC9CF  |.  0FB746 02     MOVZX EAX,WORD PTR DS:[ESI+2]            //读取上一节的长度
77FCC9D3  |.  C1E0 03       SHL EAX,3
77FCC9D6  |.  2BF8          SUB EDI,EAX
77FCC9D8  |.  3BFE          CMP EDI,ESI                              //判断前面的那个堆块是不是只和一块空表连着的,如果连着的判断是不是尾块
77FCC9DA  |.  74 0A         JE SHORT 77FCC9E6
77FCC9DC  |.  F647 05 01    TEST BYTE PTR DS:[EDI+5],01              //观察前一块的是否是占用态
77FCC9E0  |.^ 0F84 98E9FFFF JZ 77FCB37E

5.然后就进行了相加的操作,那个Call 778953A的作用应该是检测那个堆块所对应的链表。

77FCB37E  |> /8B4D 10       MOV ECX,DWORD PTR SS:[EBP+10]
77FCB381  |. |0FB707        MOVZX EAX,WORD PTR DS:[EDI]
77FCB384  |. |8B09          MOV ECX,DWORD PTR DS:[ECX]
77FCB386  |. |03C8          ADD ECX,EAX                              //上一节堆块的大小再加上这一节的进行合并
77FCB388  |. |81F9 00FE0000 CMP ECX,0FE00
77FCB38E  |. |0F87 52160000 JA 77FCC9E6
77FCB394  |. |807D 14 00    CMP BYTE PTR SS:[EBP+14],0
77FCB398  |. |0F85 6A370000 JNE 77FCEB08
77FCB39E  |> |57            PUSH EDI                                 //指向Free的那个堆块的前一个堆块
77FCB39F  |. |53            PUSH EBX                                 //指向整个堆块的最前面
77FCB3A0  |. |E8 95E1FBFF   CALL 77F8953A                            // ntdll.77F8953A

6.先把之前的那个表从链表中拿出来,同时还检测了这块上再上面一块,如果这再上面一块不是占用态的话还要继续进行合并。再把堆块最前面对大小的说明的那一部分进行改动。

77FCB3A5  |.  8B4F 0C       MOV ECX,DWORD PTR DS:[EDI+0C]
77FCB3A8  |.  8B47 08       MOV EAX,DWORD PTR DS:[EDI+8]
77FCB3AB  |.  3BC1          CMP EAX,ECX                              //看看前面的再前面的那个堆块是不是只和一块空表连着的
77FCB3AD  |.  8901          MOV DWORD PTR DS:[ECX],EAX
77FCB3AF  |.  8948 04       MOV DWORD PTR DS:[EAX+4],ECX             //把和Free合并的那个堆块从链表中取出来
77FCB3B2  |.  74 4D         JE SHORT 77FCB401
77FCB3B4  |>  8A47 05       MOV AL,BYTE PTR DS:[EDI+5]
77FCB3B7  |.  A8 04         TEST AL,04                               //检测标志位。(不是很懂
77FCB3B9  |.^ 0F85 21FDFFFF JNZ 77FCB0E0
77FCB3BF  |>  8A46 05       MOV AL,BYTE PTR DS:[ESI+5]
77FCB3C2  |.  24 10         AND AL,10
77FCB3C4  |.  A8 10         TEST AL,10
77FCB3C6  |.  8847 05       MOV BYTE PTR DS:[EDI+5],AL               //把合并进来的堆块调成空闲态
77FCB3C9  |.  0F85 CB170000 JNZ 77FCCB9A
77FCB3CF  |>  0FB70F        MOVZX ECX,WORD PTR DS:[EDI]
77FCB3D2  |.  8B45 10       MOV EAX,DWORD PTR SS:[EBP+10]
77FCB3D5  |.  8BF7          MOV ESI,EDI                              //再往上看一个堆块
77FCB3D7  |.  0108          ADD DWORD PTR DS:[EAX],ECX               //加起来
77FCB3D9  |.  0FB70F        MOVZX ECX,WORD PTR DS:[EDI]
77FCB3DC  |.  294B 28       SUB DWORD PTR DS:[EBX+28],ECX            //从总的里面减
77FCB3DF  |.  66:8B00       MOV AX,WORD PTR DS:[EAX]
77FCB3E2  |.  F647 05 10    TEST BYTE PTR DS:[EDI+5],10              //又判断是不是尾块
77FCB3E6  |.  66:8907       MOV WORD PTR DS:[EDI],AX                 //堆块头部的大小进行了替换 合并
77FCB3E9  |.  0F85 F7150000 JNZ 77FCC9E6
77FCB3EF  |.  8B45 10       MOV EAX,DWORD PTR SS:[EBP+10]
77FCB3F2  |.  8B08          MOV ECX,DWORD PTR DS:[EAX]
77FCB3F4  |.  66:8B00       MOV AX,WORD PTR DS:[EAX]
77FCB3F7  |.  66:8944CF 02  MOV WORD PTR DS:[ECX*8+EDI+2],AX         //把下一节中描述上一节大小的量进行变化
77FCB3FC  |.  E9 E5150000   JMP 77FCC9E6

6.然后又看下一节是不是占用态,不是占用态的话继续合并。

77FCC9E0  |.^\0F84 98E9FFFF JZ 77FCB37E
77FCC9E6  |>  F646 05 10    TEST BYTE PTR DS:[ESI+5],10
77FCC9EA  |.  75 0F         JNZ SHORT 77FCC9FB
77FCC9EC  |.  8B45 10       MOV EAX,DWORD PTR SS:[EBP+10]
77FCC9EF  |.  8B00          MOV EAX,DWORD PTR DS:[EAX]
77FCC9F1  |.  F644C6 05 01  TEST BYTE PTR DS:[EAX*8+ESI+5],01        //看下一节是不是占用态
77FCC9F6  |.  8D3CC6        LEA EDI,[EAX*8+ESI]
77FCC9F9  |.  74 09         JZ SHORT 77FCCA04

7.看下一节是不是尾块,不是的话继续合并、

77FCCA04  |> \0FB70F        MOVZX ECX,WORD PTR DS:[EDI]
77FCCA07  |.  03C8          ADD ECX,EAX
77FCCA09  |.  81F9 00FE0000 CMP ECX,0FE00
77FCCA0F  |.^ 77 EA         JA SHORT 77FCC9FB
77FCCA11  |.  807D 14 00    CMP BYTE PTR SS:[EBP+14],0
77FCCA15  |.  0F85 FB210000 JNE 77FCEC16
77FCCA1B  |>  8A47 05       MOV AL,BYTE PTR DS:[EDI+5]
77FCCA1E  |.  24 10         AND AL,10
77FCCA20  |.  A8 10         TEST AL,10                               //看是不是尾块
77FCCA22  |.  8846 05       MOV BYTE PTR DS:[ESI+5],AL
77FCCA25  |.  75 4B         JNZ SHORT 77FCCA72
77FCCA27  |>  57            PUSH EDI                                 //下一节的地址
77FCCA28  |.  53            PUSH EBX                                 //堆块的地址
77FCCA29  |.  E8 0CCBFBFF   CALL 77F8953A                            //\ntdll.77F8953A
77FCCA2E  |.  8B4F 0C       MOV ECX,DWORD PTR DS:[EDI+0C]
77FCCA31  |.  8B47 08       MOV EAX,DWORD PTR DS:[EDI+8]
77FCCA34  |.  3BC1          CMP EAX,ECX                              //看看是不是表里只有一个
77FCCA36  |.  8901          MOV DWORD PTR DS:[ECX],EAX
77FCCA38  |.  8948 04       MOV DWORD PTR DS:[EAX+4],ECX             //把表改成指向自己,清空    
77FCCA3B  |.^ 0F84 12E9FFFF JE 77FCB353

8.然后修改堆块头,改下一节对上一节大小的说明

77FCCA41  |> \8A47 05       MOV AL,BYTE PTR DS:[EDI+5]
77FCCA44  |.  A8 04         TEST AL,04
77FCCA46  |.^ 0F85 CBE6FFFF JNZ 77FCB117
77FCCA4C  |>  0FB70F        MOVZX ECX,WORD PTR DS:[EDI]
77FCCA4F  |.  8B45 10       MOV EAX,DWORD PTR SS:[EBP+10]
77FCCA52  |.  0108          ADD DWORD PTR DS:[EAX],ECX               //上面加的又加上下一节
77FCCA54  |.  0FB70F        MOVZX ECX,WORD PTR DS:[EDI]
77FCCA57  |.  294B 28       SUB DWORD PTR DS:[EBX+28],ECX            //从总的里面减
77FCCA5A  |.  66:8B08       MOV CX,WORD PTR DS:[EAX]
77FCCA5D  |.  F646 05 10    TEST BYTE PTR DS:[ESI+5],10              //确认不是尾块
77FCCA61  |.  66:890E       MOV WORD PTR DS:[ESI],CX                 //又一次修改堆块头的大小
77FCCA64  |.^ 75 95         JNZ SHORT 77FCC9FB
77FCCA66  |.  8B08          MOV ECX,DWORD PTR DS:[EAX]
77FCCA68  |.  66:8B00       MOV AX,WORD PTR DS:[EAX]
77FCCA6B  |.  66:8944CE 02  MOV WORD PTR DS:[ECX*8+ESI+2],AX         //修改下一节中对上一节的大小的描述
77FCCA70  |.^ EB 89         JMP SHORT 77FCC9FB

9.找一个空闲的空表放进去

77FCC8E6  |.  8066 05 10    AND BYTE PTR DS:[ESI+5],10               //确认堆块的Flag位
77FCC8EA  |.  0FB745 D0     MOVZX EAX,WORD PTR SS:[LOCAL.12]
77FCC8EE  |.  8D9CC7 780100 LEA EBX,[EAX*8+EDI+178]                  //找一个Freelist
77FCC8F5  |.  895D C4       MOV DWORD PTR SS:[LOCAL.15],EBX
77FCC8F8  |.  391B          CMP DWORD PTR DS:[EBX],EBX               //看这个表是不是空闲的空表
77FCC8FA  |.^ 0F84 CBF5FFFF JE 77FCBECB
77FCC90C  |.  8918          MOV DWORD PTR DS:[EAX],EBX
77FCC90E  |.  894E 0C       MOV DWORD PTR DS:[ESI+0C],ECX
77FCC911  |.  8901          MOV DWORD PTR DS:[ECX],EAX
77FCC913  |.  8943 04       MOV DWORD PTR DS:[EBX+4],EAX             //按照顺序改堆块里面的地址
77FCC916  |.  8B45 D0       MOV EAX,DWORD PTR SS:[EBP-30]            //堆溢出就在这一个点,就把那个指针替换掉
77FCC919  |.  0147 28       ADD DWORD PTR DS:[EDI+28],EAX            //改空表里面的地址
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值