2007年4月4日星期三

病毒之后

究竟是31号还是1号中的毒,我也不记得了,总之这是个蛮特别的愚人节。感觉,有一点复杂。

虽然裸奔习惯的确不好,可这次事件我就算装了什么病毒监控也一样没用。有人提到说他25号就已经中毒了,那离我在网上找寻解决办法至少有五天。如果是我花了钱,买了一套杀毒软件,却发现不但没有尽到保护责任,反应速度还这么慢,那种感觉肯定很糟。一众杀毒软件商们,看来也就这样了。

在刚发现感染病毒的时候,我并没太当一回事。利用了Windows的新漏洞是挺先锋,可病毒本身并没什么特别的。实际上我用Ruby写的清除程序原始版本,只有50来行。包括分析病毒行为和写代码在内,也不过三、五个小时。

不但如此,我甚至还觉得有一点好玩。毕竟我自己的机器几乎没中过毒,该病毒修改可执行文件的手法也不邪恶,所以刚开始也就没有感到作者很恶意。而且病毒试图在hosts文件里屏蔽的那些网站,都不是什么好去处。过招谈不上,似乎是一种交谈的感觉。他给我弄了点小麻烦,可摊子还没烂到无法收拾。只可惜后续的发展,让事情的味道有了些变化。

先是有很多人在我那篇《遭遇Sysload3.exe》里留言,好像认定了我会放出一个“病毒专杀软件”出来一样。我本来只是想弄个rb2exe,帮帮找到我这里来的人而已。可是留言的人不止一个两个。控制台?命令行?想想也知道那对普通用户来说意味着什么。

既然能帮到那么多人,那这件事就不能不管。而且当时在Google里搜索sysload3.exe,我这里排在搜索结果第一位,就更确定了我的想法。于是去下了一个VB6精简版,花了一个晚上写出第一个版本的rmsl3.exe。真的很久很久没用VB6了,手很生。现在让我写VB6的代码,肯定不太舒服,但怀念的感觉倒是蛮真实的。

为了尽快放出程序,导致界面很简陋,功能也不完善,所以我写了个尽可能详细的说明。用户环境千差万别,没经过什么测试,就对硬盘里成百上千个文件进行读写可不是闹着玩的。我注明了不要随意转载,因为我不想自己写的代码给任何人带来损失。不过还是有人转了,说明也有,就一句话,还有一句对作者的感谢。

我没有责怪那位转载者的意思。在找不到解决办法的情况下发现我的程序,恐怕我说什么都值得试一试。转载如果能帮到更多的人,当然也不违背我的本意。可我仍旧有一种沟通困难的感觉,是理念和角度的不同,还是单纯太毛躁?或许我也不该这么谨小慎微,该对自己的代码更有自信才对。

至于病毒本身和其作者。因为我赶着写程序,直到第一个版本完成了,我才发现这个病毒会篡改php、html等文件的内容。如果跑IIS的Web服务器感染了这个病毒,那可真是一次撂倒一大片。这个发现,让我对病毒作者的感觉有了很大变化。

实际上并不是所有的病毒都只干“坏事”,像CIH那样的毕竟是少数。有些病毒只是占你一点硬盘、耗你一点内存,甚至还有帮你杀其他病毒和堵系统漏洞的病毒。虽然这种未获许可的行为仍然不具有正确性,可我宁愿认为这是高手们的“调皮”。多多少少,我能体会这种感觉。

可是这个病毒篡改php等文件的方法是直接覆盖。这与感染可执行文件的方式不同,是没有办法恢复原始内容的。数据无价,硬盘坏了“想死的心都有”,这话我听过很多次。我认为这是界限,所以“调皮”变成了“恶意”,我甚至有那么点失望的感觉。

不管怎么说,今年的愚人节早就过了。我想这个病毒的作者,应该也看不到我这篇东西。目前rmsl3.exe已被下载了70来次,Google里“sysload3.exe”这个关键字的搜索结果,前三页都没有我的链接,大概不会有多少人找上门来了。所以,这件事情可以告一个段落了。

2007年4月1日星期日

遭遇sysload3

因为机器比较老旧,我一向都是裸奔,下了什么东西运行以前,顶多用AVPDOS32扫描一下。这的确不是一个好习惯,以下就算是一个教训。

事情是这样的,昨天找了几个PS2相关的软件,就发现系统不太正常。执行一些控制台程序,例如ruby.exe、lftp.exe、grep.exe等,会弹出一个新控制台窗口,隐隐觉得不对。打开任务管理器一看,有若干个notepad.exe和iexplore.exe进程。可我当时一个记事本都没打开,肯定有问题。

查看系统启动加载项,发现了诸如iexpl0re.exe、c0nime.exe、winlog0n.exe之类的东西,显然是中木马了。我首先想到的就是360安全卫士,奇虎从良以后这个产品的口碑还是不错的。下载运行,查出了两个恶意软件cmdbcs和upxdnd。强制停掉进程后修复,并把加载项及其指向的文件全部删掉后重启,这下360报告没有找到恶意程序了,可事情还没完。

我上了一会网后还是觉得不对,因为硬盘莫名其妙响了一阵。打开任务管理器,又是若干个notepad.exe和iexplore.exe,注册表的情况也一样,那些木马又都回来了。因为重启以前我仔细检查过,所有的自动加载项和系统服务应该都没有问题。这说明木马并不是在系统启动时加载的,而且这次重启后我并没有运行任何可疑的程序。看来我遇到的并不仅仅是木马那么简单,很有可能是一个会感染可执行程序的病毒。

正好早就听说有款叫“驱逐舰”的杀毒软件用了俄国大蜘蛛Dr.Web的引擎,资源占用很少。下回来之后才发现用网上流传的序列号可以安装,但无法升级病毒库,还得用专门的第三方升级工具才行。早知如此我就下试用版了,反正可以用一个月。这是题外话,以后再说。

用驱逐舰扫描后发现了很多可疑文件,病毒名称为DLOADER.Trojan,括号说明“智能启发”。资料里说,所谓“智能启发”就是查找未知病毒的功能。可麻烦的是,如果选择清除病毒,驱逐舰会把可疑文件整个删掉。我硬盘上被感染的文件不止一个两个,如果全删等于是完完全全重作系统,那还不得累死。再尝试用最新病毒库的卡巴斯基来查,这回更是一无所获。八成是个新病毒,这些个杀毒软件都还没反应呢,只好死马当成活马医了。

想了想,Loader是加载器的意思,D要么是Double要么是Dll。从控制台程序会弹出一个新窗口执行看,病毒可能是修改了可执行文件,先执行了他自己的代码后再新开一个进程执行原始程序。挑了两个被感染的文件和原始文件对比一下,发现都多出了12808字节。如果只是单纯把两个可执行文件合并成一个,那感染文件里肯定有两个PE头。

确认的办法很简单,每个可执行文件头部都有一句“This program cannot be run in DOS mode”(不同的编译器不一样,这是VC的),搜就是了。果然,在偏移量0×3200找到了第二个PE头。0×3200是十进制的12800,试着把感染文件头部12800字节和最后的8字节去掉,与原始文件对比,相符。我应该是不需要重装系统了,松了一口气……

恢复文件有眉目了,顺带我还发现了些挺有趣的东西。这个病毒会调用IE去下载文件,这样至少能躲过防火墙。下载的目的文件是http://a.2007ip.com/css.css,这实际上是一个ini文件。病毒会根据这个文件的指示下载若干个木马,上面提到upxdnd和cmdbcs就是这么来的。还有一个http://if.iloveck.com/test/hos.gif,这是个纯文本文件,用来覆盖hosts,屏蔽若干网址。UpdateMe指向的是病毒文件,也就是说这个病毒是可以通过网络升级的。

最有趣的是还是tongji那一行,这一行指向http://if.iloveck.com/test/tongji.htm。这是一个html页面,调用了CNZZ.com的统计代码。每一台被病毒感染的机器都会用IE调用这个地址,包括IP、系统版本、浏览器信息等都会被记录下来。病毒作者给“网站”取的名字叫“安装率”,可惜阅读统计报告需要密码,不然我也想看看究竟有多少人中了他的招。

好了,说正经的:

  • 病毒原始文件名为sysload3.exe,长度12800字节,MD5校验99720C731D19512678D9594867024E7E。
  • 病毒程序被执行后,会试图添加启动加载项“System Boot Check”。
  • 可执行文件被感染后增加12808字节,头部12800字节,尾部8字节。病毒体长度不定,被感染文件尾部的8字节即为病毒体长度。
  • 到目前为止,卡巴斯基无法发现该病毒,驱逐舰虽然可以发现被感染文件,但不能清除。
  • 用360安全卫士删掉恶意软件,并将注册表中的木马加载项删除后,可清除掉病毒主体。但如果有被感染文件存在,一旦执行系统将再次被感染。
  • 打开360安全卫士的保护功能,当病毒进行注册表操作时会报警,可防止病毒被添加进系统加载项,这样能进行带毒操作。可我不清楚病毒代码究竟干了多少事,所以这不是个好主意
  • 我不想一个个去试那些杀毒软件了,所以会尝试自己写一个清除程序。如果在看到这篇东西时兄台的杀毒软件仍然对付不了这个病毒,可以留言问问我。

Update

因为我似乎是网上第一个放出该病毒删除工具的人,因此这一篇也成为我写blog以来,访问和留言人数最多的东西。当时还有人跑来留言,为别的某些网站和论坛打广告拉人,想想也蛮有意思的。现在事件已经过去,问题也都解决了,所以这里不再提供我所写的病毒删除工具,同时把文字恢复到其本来的样子。

2007年3月3日星期六

Torrent文件格式

ed2k链接包含了文件长度和md4值,有了这两部分信息就很容易验证某个文件是否正确。而我在用BT下载某个文件前,有时想检查一下本地是否已经有了该文件的副本。可是很遗憾,我的目的无法达到,或者说不一定能够达到。

本文只涉及Toreent文件格式,TheoryOrg有一份v1.0的BT协议文本,有兴趣了解BT协议其他部分的可以自己看一下。

Torrent文件格式简单得可爱,其使用了一种叫bencoding的数据表达方法,支持四种数据格式:字符串、整数、列表、字典。一个Torrent文件就是一个经过编码的bencoding字典。bencoding的编码方式如下:

字符串
格式为“[[长度]:[数据]]”。其中第一部分长度为ASCII表示的十进制数字,两部分中间用冒号分隔。例:4:spam。
整数
格式为“[i[数据]e]"。开始标识i和结束标识e之间也是用ASCII表示的十进制数字,bencoding允许表示负数和0,所以i-3e和i0e是合法的,但不允许有先导0,故i04e非法。
列表
格式为“[l[bencoded数据]e]”。例如:l4:spami-3ee表示["spam", -3]。需要注意的是bencoding列表是有序的,解码和读取时不能打乱顺序。
字典
格式为“[d[bencoded字符串][bencoded数据]e]”。bencoding字典包含2N个bencoded数据,每2个一对,第一个字符串为[数据名],第二个为[]。例如:d3:who2:me4:lovel1:a1:bee表示{"who" => "me", "love" => ['a', 'b']}。

有了以上说明就足够解码一个Torrent文件了,而一个合法的Torrent文件包含如下内容:

info
包含文件信息的一个字典。info有单文件和多文件两种,详细说明见下。
announce
tracker服务器地址。
announce-list
可选,包含其他可用tracker服务器地址的列表。
creation date
可选,torrent文件创建时间,UNIX标准格式,表示自UTC1970年1月1日0时以来的秒数。
comment
可选,torrent创建者写的备注。
created by
可选,创建torrent文件的程序名和版本。

除以上外,Torrent文件可能还包含encoding、nodes等内容,大概是由后续版本的BT协议规定的。nodes有可能跟DHT有关。

Info字典有两种格式,以下为两种共有的部分:

piece length
每块数据的长度。
pieces
字符串格式,长度除以20即为总块数,每20字节又表示1块数据的SHA1值。
private
值为1或0的整数,可选。看不太懂什么意思,似乎是说如该值为1,则只能从torrent文件中指定的tracker服务器找别的peer,不设或为0则不限制。

只包含一个文件的Info字典:

name
文件名。
length
文件长度。
md5sum
可选,32字节长的文件MD5值。

包含多个文件的Info字典:

name
存放文件的目录名。
files
包含多个字典的列表,每个字典表示一个文件的信息。

files列表中的每个字典包含的内容:

length
文件长度。
md5sum
可选,含义同上。
path
包含一个或多个字符串的列表。0到-2个表示文件目录,最后一个表示文件名。例如["dir1", "dir2", "file.ext"]表示文件保存在dir1/dir2子目录下,文件名为file.ext。

因为BT上传和下载都用不到md5sum值,即使下载完成验证文件,也可以通过pieces包含的SHA1值来完成,所以BT协议把md5sum标记为可选。我随手找来百多个torrent文件检查了一下,创建torrent文件的程序包括Azureus、BitComet和uTorrent,没有一个torrent文件包括了md5sum。这也难怪,SHA1和MD5是完全不同的算法,要加入md5sum势必延长torrent文件的创建时间,能省自然就省了。可这样的省略,也使得我上述的目的很难达到了。

最单纯的情况下,torrent文件只包括一个目标文件的信息,那只要从本地文件创建一个torrent,再比较两个torrent的pieces部分,就可以判断出本地文件是否为目标文件的副本。问题是很多torrent文件都包括了不止一个目标文件,如果其余文件只是txt、nfo、jpg等,还可以下载回来一并验证。但如果torrent包括几个大型文件的信息,又只想验证本地是否有其中一个文件的副本,则几乎没办法做到了。

假如有md5sum,一切会变得非常简单。我测试所用的那些torrent中,绝大部分都是BitComet创建的。不知道写信给作者提建议,他会不会理我。