文章作者:cocoruder
信息来源:安全焦点技术论坛
author:cocoruder
date:15/12/2005
sowhat的漏洞报告
http://www.nsfocus.net/vulndb/7069
偶在使用金山词霸的时候也遇到过这种问题,造成系统假死机,本以为真是个溢出问题,或许可以利用利用,写一大段E文诱惑某人来看:),于是在假死机的状态下呼出Softice,发现堆内存被疯狂申请,最终确定只是个内存泄露问题:P,下面给出细节。偶测试的版本是金山词霸2003,点帮助后显示的版本信息为6.0.0.0。
金山词霸主程序xdict.exe负责与其注射到每个进程里的插件(Cjktl32.dll)通信,获取取得的字符,并进行处理。
问题出现在xdict.exe的sub_44e3b0函数中,如下:
复制内容到剪贴板
代码:
.text:0044E3B0 sub esp, 9Ch
.text:0044E3B6 push ebp
.text:0044E3B7 push esi
.text:0044E3B8 push edi
.text:0044E3B9 mov edi, ecx
.text:0044E3BB xor ebp, ebp
.text:0044E3BD mov [esp+0A8h+var_84], edi
.text:0044E3C1 mov eax, [edi+48h]
.text:0044E3C4 cmp eax, ebp
.text:0044E3C6 jz short loc_44E3D7
.text:0044E3C8 mov eax, [eax]
.text:0044E3CA cmp eax, ebp
.text:0044E3CC jz short loc_44E3D7
.text:0044E3CE push eax ; BSTR
.text:0044E3CF call ds:SysStringLen ;求取词长度
.text:0044E3D5 jmp short loc_44E3D9
...
.text:0044E4CA mov ecx, edi
.text:0044E4CC mov esi, eax
.text:0044E4CE call sub_44D560 ;这个call根据取词Buff计算SumTableCode大小
...
.text:0044E578 loc_44E578: ; CODE XREF: sub_44E3B0+158j
.text:0044E578 mov eax, [edi+5D8h]
.text:0044E57E mov edx, [esp+0ACh+var_7C]
.text:0044E582 sub eax, ebp
.text:0044E584 cmp edx, eax ;SumTabldeCode与一固定值比较,大于等于则跳
.text:0044E586 jge short loc_44E5ED
...
...
.text:0044E5ED loc_44E5ED: ; CODE XREF: sub_44E3B0+1D6j
.text:0044E5ED mov ebp, [esi+38h]
.text:0044E5F0 mov esi, [esi+3Ch]
.text:0044E5F3 mov edi, [esp+0ACh+var_94]
.text:0044E5F7 mov ecx, [esp+0ACh+var_84]
.text:0044E5FB push esi
.text:0044E5FC push ebp
.text:0044E5FD push edi
.text:0044E5FE push eax
.text:0044E5FF mov [esp+0BCh+var_80], esi
.text:0044E603 call sub_44E970 ; 拷贝当前取词并拷贝至1堆内存,并取得0x0000结尾,
.text:0044E603 ; 正常应返回内存Unicode字节数,异常返回0
.text:0044E608 add eax, ebp
.text:0044E60A mov [esp+0ACh+var_88], eax
.text:0044E60E lea ecx, [eax-1] ;ecx=-1
.text:0044E611 cmp ecx, esi ;
.text:0044E613 jge loc_44E70C ;小于,不跳
.text:0044E619 mov [esp+0ACh+var_24], edi
.text:0044E620 jmp short loc_44E626 ;进入堆内存申请代码
.text:0044E622 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0044E622
.text:0044E622 loc_44E622: ; CODE XREF: sub_44E3B0+350j
.text:0044E622 mov eax, [esp+0ACh+var_88] ; 进入1次,分配一次堆内存。
.text:0044E626
.text:0044E626 loc_44E626:
.text:0044E626 mov esi, [ebx+8]
.text:0044E629 mov edx, [esp+0ACh+var_9C]
.text:0044E62D dec eax
.text:0044E62E push 0FFFFFFFFh
.text:0044E630 lea ecx, [esi+1]
.text:0044E633 mov [esp+0B0h+var_1C], eax
.text:0044E63A mov eax, [esp+0B0h+var_8C]
.text:0044E63E push ecx
.text:0044E63F mov ecx, ebx
.text:0044E641 mov [esp+0B4h+var_20], ebp
.text:0044E648 mov [esp+0B4h+var_18], edx
.text:0044E64F mov [esp+0B4h+var_14], eax
.text:0044E656 call sub_426B60 ; 这个函数分配了堆内存
...
.text:0044E6D8 push ecx
.text:0044E6D9 mov [esp+0B0h+var_8C], ebp
.text:0044E6DD mov ebp, [esp+0B0h+var_88]
.text:0044E6E1 push ebp
.text:0044E6E2 push edi
.text:0044E6E3 push edx
.text:0044E6E4 mov ecx, esi
.text:0044E6E6 mov [esp+0BCh+var_9C], 0
.text:0044E6EE call sub_44E970 ; 和0044e603处同样的函数,SumTableCode>0x1f8,返回0
.text:0044E6F3 mov ecx, [esp+0ACh+var_80]
.text:0044E6F7 add eax, ebp
.text:0044E6F9 mov [esp+0ACh+var_88], eax
.text:0044E6FD dec eax
.text:0044E6FE cmp eax, ecx ; sub_44e970返回0时eax=-1,跳,构成死循环
.text:0044E700 jl loc_44E622
.text:0044E706 mov edi, [esp+0ACh+var_94]
.text:0044E70A mov esi, ecx程序先通过函数sub_44E970遍历取得的每个字符,并根据每个字符计算出一个SumTableCode值,这个值再和一固定值StaticCode相比较,大于等于则会进入sub_44E970子函数,此函数又比较了一遍SumTableCode和StaticCode,大于则认为出错,返回0。主函数在处理这个函数的返回值时出现错误(未考虑返回0的情况,直接减1=-1),导致进入死循环,不断分配堆内存,从而导致内存泄露。
sub_44E970子函数里计算SumTableCode的算法简要:
复制内容到剪贴板
代码:
for (i=0;i<sizeof(plain)-1;i++)
{
SumTableCode=SumTableCode+BaseTable[plain[i]*3*4]+BaseTable[plain[i]*3*4+4]+BaseTable[plain[i]*3*4+8]
}BaseTable为一大数据表(附在后面),plain为取词缓冲区。
也就是说,SumTableCode>StaticCode就会跳到死循环中产生内存泄露,偶的机器的StaticCode恒为0x1f8,查表字符A对应的
BaseTable[plain
*3*4]+BaseTable[plain*3*4+4]+BaseTable[plain*3*4+8]=9
因此要输入至少0x1f8/9+1=57个'A'字符才能触发内存泄露,56个'A'也不会触发。
另外的一个可能是真正的溢出问题出现在其取词插件Cjktl32.dll模块中,由于触发次数有限,暂时还未得到细节:P
附:
dump出来的BaseTable复制内容到剪贴板
代码:
"\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00"
"\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00"
"\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00"
"\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00"
"\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00"
"\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00"
"\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00"
"\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00"
"\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00"
"\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00"
"\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00"
"\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00"
"\x01\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\xFF\xFF\xFF\xFF\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
"\x0B\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x0A\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00"
"\x00\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00"
"\x01\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00"
"\x03\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"
"\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00"
"\x01\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00"
"\x05\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00"
"\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00"
"\x01\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
"\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00"
"\x00\x00\x00\x00\x0D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0A\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x07\x00\x00\x00"
"\x01\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
"\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x08\x00\x00\x00\x01\x00\x00\x00"
"\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00"
"\x01\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x0C\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x0B\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x08\x00\x00\x00\x01\x00\x00\x00"
"\x00\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
"\x09\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x0B\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x0D\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x0A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0A\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x08\x00\x00\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x03\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00"
"\x01\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00"
"\x01\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"
"\x05\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\xFF\xFF\xFF\xFF\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x03\x00\x00\x00"
"\x01\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x0B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x01\x00\x00\x00"
"\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0B\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00"
"\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00"
"\x04\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00"
"\xFF\xFF\xFF\xFF\x08\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00";