2007年10月20日星期六

Windows Vista UAC的一处严重的愚蠢设计(之二)

为了搞清楚是什么程序或者服务造成这个问题,我打开了我的两个工具:IceSword和ProcessMonitor(这两个经常手工杀毒的肯定至少用过)。

先开IceSword,选中监视进线程创建,运行那个问题安装包。很快我就发现,有一个svchost进程和一个叫consent.exe的进程异常活跃。

(注意其中那个lsm.exe不是特殊程序而是相当于XP/2003的winlogon.exe和部分lsass功能的程序)。

consent.exe是在复制文件一段时间后才真正运行的。如果在它出现到UAC窗口出现之间的一段时间把这个进程结束掉,什么错误都不会发生,而那个临时文件已经消失了。为了继续调查,我设置了几下ProcessMonitor的规则。

证明那个服务在疯狂读取原文件并复制到%windir%\temp下,consent只是读那个临时文件而已。知道了那个svchost.exe的pid,也就容易弄清楚那个服务到底是何方神圣了。很快就通过IceSword查找到这个svchost的模块里有mmcss.dll(那个造成放声音减网速的MMCSS服务),BITS.dll(Windows Update的那个背景传输服务)等等东西,看上去都是属于那netsvcs组。进一步查看,反复尝试对这个组的各服务进行操作,发现有一个怎么也结束不掉(无响应)的服务──AppInfo。这是这个服务的说明:

辅助管理权限?和UAC的功能一样!难道是它?因为这个服务结束不掉(不管是用MMC,用net stop还是sc stop都无响应),只好先将其设置为禁用,再结束掉它的母svchost.exe。

再次运行那个安装包,结果……

果然。现在这个服务无法启动,任何要求UAC提升权限的东西都无法启动了,那个临时文件也根本没有被创建。但是为什么要求吞食硬盘空间的却是这个作为UAC功能之核心的服务呢?

我可以粗略分析出UAC对于一个安装包/自解压EXE文件是如何工作的:

(1)Win32 API Winexec函数运行该程序

(2)检测安装包的文件名和属性中的信息,发现一些特征如关键词"setup""install"一类或者在应用程序兼容性数据库(我目前发现它存在在%windir%\apppatch下的三个.sdb文件中)发现相关项或者在应用程序的内嵌/外挂manifest中发现特殊要求(如icesword.exe)

(3)Appinfo服务复制这个文件到%windir%\temp下

(4)consent程序检验这个临时文件的数字签名等信息,负责弹出UAC确认窗口

(5)如果选允许,consent以自身的高权限运行原.exe文件并退出

(6)appinfo服务检测到consent退出,删除临时文件

用伪代码可以这么描述

WinExec(string filename) /*这里的filename指完整路径名*/

{

bool issecure;

issecure=SecCheck(filename));

if(!issecure)

{

UAC(filename);

return 0;

} /*(2)*/

execFile(filename);

}

UAC(string filename)

{

string tempfilename;

string consentline="consent.exe -v origfile= ";

strcat(tempfilename, Getenvironmentstrings("Windir"));

strcat(tempfilename, "\Temp");

strcat(tempfilename, tempNamegenerate(GetNamefromFullpath(filename)));/*生成临时文件的完整路径名*/

Copyfile(filename, tempfilename); /*(3)*/

strcat(consentline, filename);

strcat(consentline, " tempfile= ");

strcat(consentline, tempfilename);

execFile(consentline, suspendwhenrunning); /*(4)(5)*/

deleteFile(tempfilename);/*(6)*/

}

我发现这个问题,就是发生在第二步。第二步失败后并没有跳到第6步。微软要做个权宜之计的修正,只需要把

Copyfile(filename, tempfilename); 这里改成if(!Copyfile(filename, tempfilename)){deleteFile(tempfilename);return 0;}就没问题了;不过为什么一定要复制文件到系统目录呢?

没有评论:

发表评论