前不久,在使用虚拟机的时候,由于在虚拟机上新安装了一个即插即用的虚拟驱动,暂且叫它 x.sys,没想到这就是祸起的开始。由于这个驱动不是很完善,所以在该驱动安装后,我重启了系统(这里的系统都是指虚拟机的系统),结果悲剧发生了。当系统出现了加载进度条后,等了无限长的时间依然没有引导进入用户界面。即使作为一个程序员,我也感到了束手无策,因为我没有备份这个系统,难道要重新安装一次,这显然只有网管能干得出来,所以我决定尝试一下修复办法。
首先被我想到的当然就是进入安全模式,因为我在安全模式下修复过无数次的系统,相当有经验,之所以我认为安全模式可以进入,是因为有些驱动在安全模式下是不加载的,在安全模式下一般只会加载一些硬件相关的驱动,尤其是一些存储驱动,即使连网卡驱动也可以选择不加载。由于 x.sys 是虚拟 scsi 小端口驱动,或许可能也许不加载吧,我抱着试一试的心情选择了安全模式,但实验结果令人沮丧,该驱动肯定加载了,因为系统依然卡在了进度条加载的地方,然后就是 loop around ,此路不通。那我又抱着试一试的心情试了一下启动最后一次正确的配置,结果最后一次正确的配置,结果再一次的失败。
到了这般地步,一般人可能会放弃了对这个系统施救,但好奇心让我决定做最后一次尝试,因为为了调试,之前我对该系统添加了一个调试启动项,可能这就是希望的开始。
难道我们要调试一下系统卡在了什么地方,显然这种方法非常的耗时,说不定还不能得到我们希望的结果。那就换一种思路,如果想让该系统正常启动,只要删除掉我最后安装的 x.sys 驱动就可以了,但这是一个悖论,系统都加载不了,如何删除(因为我没有 pe 盘,无法拿其它系统引导)。那就想办法不让该驱动加载,然后等正常进入后再删掉,这样就好了,顺着这个思路,我们知道,内核由 ntldr 加载进内存后就开始了初始化过程,包括各个组件,如内存管理,进程管理,I/O 系统,在 I/O 系统初始化过程中,会加载引导启动驱动和系统启动驱动,而加载驱动都是由IopLoadDriver 这个系统调用来完成,那么我们在这个函数处打上断点,如果看到是加载 x.sys 驱动,那么就直接返回失败就可以了。启动 Windbg ,单机调试,在 IopLoadDriver 处设置断点,通过分析,我发现它有打开注册表,拼接出完整加载路径的操作(IopBuildFullDriverPath),我就在拼接之后打上断点,如图:
(图断点处的意思是比较返回值,若失败则退出)
调试发现,该函数的第三个参数PUNICODE_STRING,即 ebp – 5c 即为一个 UNICODE_STRING 的地址,该字符串就是将要加载的驱动的全路径如下图。
这样就简单了,我们观察如果加载的驱动是我们自己的驱动,那么就修改 eax 为 -1, 此时检查就是失败,该函数失败返回。
根据这个思路,我把所有加载x.sys 的地方全部修改为失败返回,结果可想而知,系统成功加载进入了,终于松了一口气,系统进入之后,赶紧手动删除了 x.sys ,然后给虚拟机做了一次备份。
这场有意义的修复战就这么顺利结束了。