-
-
[旧帖] [原创]Windbg堆调试时页堆使用小结 0.00雪花
-
发表于: 2015-9-17 17:15 2327
-
Windbg堆调试时页堆使用小结
使用工具:Windbg,Application Verifier
页堆分为:普通页堆和完全页堆
1、 普通页堆实现原理是通过填充模式(增加了页堆元数据,包括请求堆块大小、实际的大小,它是在原有的堆元数据后添加了一个32字节或0x20的页堆元数据,假如Heapalloc分配的堆起始地址为0019e260,那么查看内存数据时就要dd 0019e260-0x20)来检测堆块的破坏,不足之处是需要在发生对破坏之后再次调用堆管理器来验证对的完整性,这样检测具有一定的滞后性,查看栈回溯信息时,异常信息定位不准确(或者说不能实时检测出堆破坏)
如下图:命令dd 0019e260-0x20
这个页堆元数据是_DPH_BLOCK_INFORMATION数据类型,通过如下命令查看(在这个元数据中+0x018处是StackTrace栈回溯信息),通过dds StackTrace查看栈回溯信息。(这里不做实验演示了,感觉用处不大)
2、 完全页堆中除了特定的填充模式外还为每一个堆块添加了防护页(Guard Page),这个防护页是不可访问的内存页,它可以实时检测出堆破坏的地方。
如下面是堆上溢的实例:
正常情况下堆溢出导致访问异常:
栈回溯信息:
因为启用普通页堆时,栈回溯时信息信息并不完整,所以一般调试堆异常时都用完全页堆:
通过在该函数返回出下断点,中断到这里后再查看堆栈信息和指令流水线来分析程序异常,或许不能一次准确定位,可以在栈回溯中向下继续下断点并查看,如上图可以在010012a8附近或者上一层出01001302附近处下断点。优先考虑在010012a8-0x10处下断点,查看周围信息和参数(可以提前在指令区定位到010012a8处查看上下文确定具体断点处,本例中选择0100128e处下断点)。如下图所示:
再次测试程序执行到断点处,分析指令(这里已经去掉应用验证管理器页堆application verifier)
执行到010012a2处,进入这个函数后,启用堆页时参数信息情况:
不启用堆页时信息情况
栈回溯后发现这里环境变量也启用堆页有区别,原因是因为启用页堆后在各个block后面都有禁止访问内存页导致,所以这个图片中信息是准确的,不妨可以到堆 00080000处查看堆信息(或者通过查看该堆中freelist信息就可以看到是分配的这个地址或者追踪指令区Heapalloc时返回的申请堆块地址,本例中可以在这里查看eax中的值)。
复制完后到00083148内存去查看:
到此就可以确定覆盖的具体位置,然后再根据实际情况判断如本例中分析指令序列确认分配堆大小,再判断溢出位置。
最后在堆释放后会有两种情况,①释放到freelist中②释放到lookaside中(如果开启旁视列表,优先释放到lookaside中),本例中释放到lookaside中:
最后再解释下栈回溯时,检索信息:以下图为例:
① 进入函数后,在当前函数中EBP位置,②该函数退出时返回地址③进入该函数时传进来的参数。
使用工具:Windbg,Application Verifier
页堆分为:普通页堆和完全页堆
1、 普通页堆实现原理是通过填充模式(增加了页堆元数据,包括请求堆块大小、实际的大小,它是在原有的堆元数据后添加了一个32字节或0x20的页堆元数据,假如Heapalloc分配的堆起始地址为0019e260,那么查看内存数据时就要dd 0019e260-0x20)来检测堆块的破坏,不足之处是需要在发生对破坏之后再次调用堆管理器来验证对的完整性,这样检测具有一定的滞后性,查看栈回溯信息时,异常信息定位不准确(或者说不能实时检测出堆破坏)
如下图:命令dd 0019e260-0x20
这个页堆元数据是_DPH_BLOCK_INFORMATION数据类型,通过如下命令查看(在这个元数据中+0x018处是StackTrace栈回溯信息),通过dds StackTrace查看栈回溯信息。(这里不做实验演示了,感觉用处不大)
2、 完全页堆中除了特定的填充模式外还为每一个堆块添加了防护页(Guard Page),这个防护页是不可访问的内存页,它可以实时检测出堆破坏的地方。
如下面是堆上溢的实例:
正常情况下堆溢出导致访问异常:
栈回溯信息:
因为启用普通页堆时,栈回溯时信息信息并不完整,所以一般调试堆异常时都用完全页堆:
通过在该函数返回出下断点,中断到这里后再查看堆栈信息和指令流水线来分析程序异常,或许不能一次准确定位,可以在栈回溯中向下继续下断点并查看,如上图可以在010012a8附近或者上一层出01001302附近处下断点。优先考虑在010012a8-0x10处下断点,查看周围信息和参数(可以提前在指令区定位到010012a8处查看上下文确定具体断点处,本例中选择0100128e处下断点)。如下图所示:
再次测试程序执行到断点处,分析指令(这里已经去掉应用验证管理器页堆application verifier)
执行到010012a2处,进入这个函数后,启用堆页时参数信息情况:
不启用堆页时信息情况
栈回溯后发现这里环境变量也启用堆页有区别,原因是因为启用页堆后在各个block后面都有禁止访问内存页导致,所以这个图片中信息是准确的,不妨可以到堆 00080000处查看堆信息(或者通过查看该堆中freelist信息就可以看到是分配的这个地址或者追踪指令区Heapalloc时返回的申请堆块地址,本例中可以在这里查看eax中的值)。
复制完后到00083148内存去查看:
到此就可以确定覆盖的具体位置,然后再根据实际情况判断如本例中分析指令序列确认分配堆大小,再判断溢出位置。
最后在堆释放后会有两种情况,①释放到freelist中②释放到lookaside中(如果开启旁视列表,优先释放到lookaside中),本例中释放到lookaside中:
最后再解释下栈回溯时,检索信息:以下图为例:
① 进入函数后,在当前函数中EBP位置,②该函数退出时返回地址③进入该函数时传进来的参数。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
谁下载
看原图
赞赏
雪币:
留言: