GDI泄漏调试工具——GdiChecker

前几个月一直在做GDI泄漏相关的工作。 相比于内存泄漏,有很多成熟的工具去检测。但是在我定位gdi泄漏之初,没有什么好用工具。基本办法的是通过任务管理器看某个进程gdi数量的变化,高级一点的是用GDIView这个程序去查看进程各种gdi类型的数量变化,可以进一步定位出是哪种gdi在泄漏,缩小范围。另一个有用的工具是GDIndicator,它可以注入到目标进程,查看gdi句柄对应对象的详细情况。比如显示出bitmap,icon,dc里面内容的样子。 显示某个gdi对象的详细信息这个功能非常有用,很多时候你就可以根据gdi对象的详情就知道是哪种资源在泄漏,哪个图片,哪种dc或者是哪种字体。还有种情况,假如第三方dll造成你程序gdi的泄漏,即使你知道某种类型的gdi正在泄漏,但是你review你自己的代码却发现对应gdi资源管理没有问题。如果你知道gdi的对象的详情,比如某个位图的样子,你就发现这可能是输入法注入进来造成的gdi泄漏。 但是GDIView和GDIndicator都有各自的缺点。GDIView分32位和64位两个独立的exe,并且不能查看到某个gdi对象的详情。而GDIndicator仅支持xp,win7下面无法使用。 我写了一个GdiChecker的程序,综合了GDIView和GDIndicator的优点。它可以同时支持显示32位和64位进程gdi的各种类型GDI数量,又可以注入到进程里面显示gdi的详情。 目前我已经把这个工具用wtl重写了一边,在github上开源了:https://github.com/plxaye/GdiChecker 也可以点这里下载GdiChecker:GdiChecker.exe... Read More | Share it now!

windbg调试内存破坏之栈溢出

当线程覆盖了为其他用途所保留的桟空间时,就是发生了栈溢出Overflow.桟溢出包括覆盖桟帧的返回地址,覆盖整个桟帧,或者消耗尽桟空间等情况。桟溢出将带来各种后果,包括程序崩溃,未预期的行为,甚至严重的安全漏洞。 运行这个程序,如果输入一些短的字符串,那么程序似乎运行起来没有问题。如果输入一个很长的字符串就会导致崩溃。 我们看下崩溃时的状态很奇怪: 乍一看,桟破坏的很严重。我们看下当前的指令指针eip   这块内存的内容是一系列?,代表这不可访问的内存。我们可以假设程序中用于控制执行流程的指令指针可能被破坏了。 我们再看看桟上的内容:   桟上的内容是aaaaaaaaaaaaaaaaa是我们输入的命令行参数。看上去桟上的内容还是正确的。 桟的ret指令会把00610061当作指令的返回地址,程序将从这个返回地址继续执行。但是我们知道00610061是无效的地址。所以崩溃的原因是执行ret指令将导致eip被设置成一个错误的返回地址,如果程序从这个错误的返回地址开始执行,将发生访问违例。 看代码,用字符串复制函数之前的桟是正确的,因此在执行字符串复制期间肯定发生了某个事件导致桟被破坏。从代码中看出HelperFunction如果复制超过MAX_CONN_LEN的字符串将发生桟溢出。 windows驱动开发包里面包含一个PREfast的工具,可以在编译时检测一些代码缺陷。从vs2008开始,已经集成了这个功能。 ... Read More | Share it now!

windbg调试符号与源代码

设置符号路径 查看现有的符号路径 重置本地符号路径 增加一个本地符号路径 增加一个指向微软符号服务器的路径 重置一个指向微软符号服务器的路径 加载调试符号 加载某个符号 重新加载所有符号 重新加载某个符号 打开、关闭显示加载符号过程的详情模式 查看加载的文件与符号 lm命令显示加载模块的信息:lm... Read More | Share it now!

使用LeakDiag调试内存泄漏

LeakDiag是一种用于检查进程内存泄漏的工具。LeakDiag功能是UMDH.exe功能的超集。UMDH只能显示标准堆管理器的分配信息,而LeakDiag还能显示com分配信息(包括内部和外部的),虚拟内存分配信息以及其它分配信息。LeakDiag在记录内存分配的栈回溯时不依赖操作系统的支持,而是通过Detours技术来拦截对内存分配的调用。这款工具的下载地址:ftp://ftp.microsoft.com/PSS/Tools/Developer%20Support%20Tools/LeakDiag/ 初始化设置 打开菜单Tools->Options,这里就是一些设置选项。你可以设置log文件的存放路径。也可以设置符号搜索路径,勾上在生成log时解析符号选项,就会把log中函数栈地址转换成函数名。不过这个解析符号的工作比较耗费时间。默认的微软符号是srv*c:symcache*http://msdl.microsoft.com/download/symbols 我建议在生成log的时候不要勾上在生成log时解析符号选项,因为这个会影响要调试进程的运行速度,导致某些跟时间相关的内存泄漏不在发生。 我们可以在事后根据dmp文件和符号文件重新去解析log文件。  记录进程内存分配 LeakDiag可以记录一下集中内存分配器的动作: Virtual... Read More | Share it now!

死锁排查

在做这个实验之前,需要先构建数据。 首先是声明两个全局临界区和两个互斥对象 四个线程 全局变量初始化以及线程创建: 整个代码比较简单,就是4个线程,会进入临界区和互斥对象。由于进入顺序不一样,就会导致死锁。 编译好后,生成了EXE:deadlocks.exe 用windbg启动调试。 并观察屏幕输出。由于每个线程都会打印日志。如果不再打印日志了就证明死锁了。 (死锁的明显现象就是线程停止,处在等待状态。调入NtWaitForSingleObject等函数中不出来。所以当产生死锁时,CPU占用一定不高。) 楼主发现屏幕只打印了两条日志就停止打印了(由于死锁发生的时机跟线程调度有关,你在测试时可能输出的日志与楼主不同,死锁时堆栈也不同,不过排错的原理是一样的)。 看样子是锁住了。 按Ctrl+Break,进入调试状态 楼主要看都有哪些线程锁住了,查一下所有线程的调用栈 通过观察调用栈,发现如下信息 0号线程是主线程,正在等待用户输出,死锁和他没关系 1号线程在等待进入临界区 2号线程也在等待进入临界区 3号线程在等待一个对象,可能是互斥量 4号线程也在等待进入临界区 5号线程是调试线程,忽略之 问题只能出在... Read More | Share it now!