/**************************************
/* 作者:半斤八兩
/* 博客:http://cnblogs.com/bjblcracked
/* 日期:2013-08-12 22:44
/**************************************
只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
听同事说win也有mount工具,好奇心驱使就搜了一下.
发现国内的著名程序员刘涛涛写了一款免费的win mount工具.
于是下载了一份就开始玩起来了.安装后发现winmount程序的界面非常漂亮友好,而且广告也很少.
甚是喜欢.图1
0x1 bug
只可惜我在使用的过程中,程序会占用100%CPU :(
0x2 BUG重现(如何产生).
首先弄个压缩软件,我当前用的是 7z 加密压缩任意一个文件.(不加密文件名).
然后用mount工具双击打开.这个时候就可以看到mount创建了一个新窗口.(输入密码框)
此时我无意中点到父窗口,发现程父窗口也是活动窗口. (原来是非模态窗口,有点意思)图2
知道是非模态窗口后,我就下意识的关闭了父窗口,有意思的事情发生了,CPU就跟打了鸡血一样,一个劲猛彪~图3
一开始我不相信自己的眼睛,我在心里想,肯定是系统或者其他什么软件出了问题了.
不可能是mount自身的问题.为了搞清楚到底是什么原因导致的CPU占用100,我决定分析它.
OD载入后,自己能想到的所有断点,都试了一遍,都没有断下来.
在一阵狂试都没有断下后,终于放弃下断点的方法了.
找了几首经典歌曲,边听边想思路.
mount占CPU的时候,操作系统虽然有点卡,但并没有卡死.
说明至少不是
for(true){;}
while(true){;}
这一类的死循环导致的卡死.
所有自己已知的如等待类函数也都下断点测试过了.
最后想就从线程下手吧.
打开线程窗口,可以看到有四个线程在拼命工作,(为了方便查看,我们可以点一下user time)图4
现在终于知道了,是这四个线程导致的,那么从entry处分析就行了.
最终分析得知导致卡死的是 kernel32.GetQueuedCompletionStatus 这个函数.
我们来看一下函数原型和介绍.
1 GetQueuedCompletionStatus 2 The GetQueuedCompletionStatus function attempts to dequeue an I/O completion packet from a specified I/O completion port. If there is no completion packet queued, the function waits for a pending I/O operation associated with the completion port to complete. 3 4 BOOL GetQueuedCompletionStatus( 5 HANDLE CompletionPort, // handle to completion port 6 LPDWORD lpNumberOfBytes, // bytes transferred 7 PULONG_PTR lpCompletionKey, // file completion key 8 LPOVERLAPPED *lpOverlapped, // buffer 9 DWORD dwMilliseconds // optional timeout value 10 );
1 6B1192E0 $ 55 push ebp 2 6B1192E1 . 8BEC mov ebp, esp 3 6B1192E3 . 83EC 0C sub esp, 0C 4 6B1192E6 . 56 push esi 5 6B1192E7 . 8B35 4870126B mov esi, dword ptr ds:[<&KERNEL32.GetQue>; kernel32.GetQueuedCompletionStatus 6 6B1192ED . 8D49 00 lea ecx, dword ptr ds:[ecx] 7 6B1192F0 > 6A FF push -1 8 6B1192F2 . 8D45 FC lea eax, dword ptr ss:[ebp-4] 9 6B1192F5 . 50 push eax 10 6B1192F6 . 8B47 08 mov eax, dword ptr ds:[edi+8] 11 6B1192F9 . 8D4D F4 lea ecx, dword ptr ss:[ebp-C] 12 6B1192FC . 51 push ecx 13 6B1192FD . 8D55 F8 lea edx, dword ptr ss:[ebp-8] 14 6B119300 . 52 push edx 15 6B119301 . 50 push eax 16 6B119302 . FFD6 call near esi 17 6B119304 . 8B45 FC mov eax, dword ptr ss:[ebp-4] 18 6B119307 . 85C0 test eax, eax 19 6B119309 .^ 74 E5 je short WMCore.6B1192F0 ; // 这里导致死循环了~ 20 6B11930B . 8B55 F8 mov edx, dword ptr ss:[ebp-8] 21 6B11930E . 8B40 14 mov eax, dword ptr ds:[eax+14] 22 6B119311 . E8 EAF7FFFF call WMCore.6B118B00 23 6B119316 .^ EB D8 jmp short WMCore.6B1192F0
通过帮助文档介绍我们知道 kernel32.GetQueuedCompletionStatus 这个函数
的意思是从指定的IOCP获取CP,当CP队列为空时.对此函数的调用将被阻塞.
阻塞?没错,阻塞就不会占用CPU100%,但是他的IO句柄是父窗口创建的 父窗口关闭了,也把句柄析构了.
他的逻辑写的是"死循环",所以句柄不存在了,就会不停的重复调用.也就会CPU占用100%了.
0x3 修复方案
1) 那个窗口改成模态窗口
2) 父窗口关闭时,应该先提前关闭非模态窗口.
这个应该也不能算是BUG吧,只能算是我误操作.
而且一般人应该也不会像我那样操作.直接关闭父窗口的
--==mount英文官方==--
--==mount中文官方==--
--==mount官方招聘==--
才发现,英文版的是PAGE是2011更新的.
中文版的PAGE是2010更新的