自己利用BCB写病毒专杀
来源:灰狐's Blog
注:本文已发表在2007年《黑客防线》第11期,转载请注明出处!
话说某天晚上,小菜我写代码写的煞是心烦,刚想放松一会儿,任务栏里的企鹅图标就不停地叫了起来,MM求救:电脑中毒了。
她的卡巴已经查到了病毒,但没有杀掉。根据扫描提示,很快在百度上找到了答案,司机报警的文件名为algsrvs.exe,经查得知是fun.xls.exe病毒,tel.xls.exe的变种之一。网上给出了一个比较完整的查杀方法,主要症状如下:
1、在“我的电脑”中双击任意驱动器时,会在新窗口中打开此驱动器;
2、不能显示隐藏文件;
3、右击任一驱动器时,在快捷菜单中的第一项显有“Auto”命令;
查杀方法:
第一步:在“任务管理器”中结束“Excel”程序(也就是algsrvs.exe进程);
第二步:删除如下四个文件:
C:\Windows\ufdata2000.log
C:\Windows\System32\algsrvs.exe
C:\Windows\System32\msfun80.exe
C:\Windows\System32\msime82.exe
第三步:在注册表在搜索“fun.xls.exe”项值,然后一一删除;
第四步:打开注册表,找到如下项
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\
Explorer\Advanced\Folder\Hidden\SHOWALL,将“CheckedValue”项删除,然后新建 一个同名的DWORD值项,设其值为“1”;
第五步:在“文件夹选项”在中选择“显示所有文件和文件夹”,取消“隐藏受保护的操作系统 文件(推荐)”的选择;
第六步:打开“我的电脑”,逐一删除各驱动器下名为“AUTORUN.EXE”和“fun.xls.exe”的这两个文件(注意,一定不能用双击打开,右击各驱动器选择“打开”命令来打开);最后重新启动计算机就大功告成了!
上面的方法讲的很详细,我根据这些提示一步步地很快就搞定了,也没什么麻烦的。不过最后她说了句:“这是实验室的电脑,我U盘上的病毒估计还在,回去把自己电脑感染下自己学习学习。”
当即晕倒,万一没搞定我岂不得累死?因为根据她的说法:她寝室同学都在用她的U盘……这可不是开玩笑的,跟女生讲电脑真的累死人……。
二话不说,立马拖出咱的RAD利器:C++ Builder 6.0,弄一个简单的专杀工具。
界面就没必要做那么复杂了,先放一个RadioGroup控件,将其Items属性改为:快速查杀、深度扫描、仅扫描U盘,Name属性改为 ConfigRadioGroup;然后添加一个Button控件,Caption属性改为:查杀;最后再加上一个Memo控件,Name属性改为 StateMemo,用来显示扫描的状态进度。
双击Button控件,进入代码编辑:
StateMemo->Clear();
if(ConfigRadioGroup->ItemIndex==2) //仅扫描U盘,因为这个比较简单
{
char filepath[MAX_PATH];
char USB='A'; //保存U盘盘符
char szDriveName[4]={0};
wsprintf(szDriveName,"C:\0");
for(szDriveName[0]='C';szDriveName[0]<'Z';szDriveName[0]++)
{ //从C到Z遍历硬盘
//使用GetDriveType判断是否为可移动磁盘
if(GetDriveType(szDriveName)==DRIVE_REMOVABLE)
{
USB=szDriveName[0]; //将U盘盘符赋给变量USB
StateMemo->Lines->Add("找到U盘"+AnsiString(USB));
sprintf(filepath,"%c:\\autorun.inf",USB); //构造完整文件名
//其实这里可以不用这么麻烦的,因为这个文件只会存在于U盘的根目录下
WIN32_FIND_DATA wfd;
HANDLE hFind = FindFirstFile(filepath, &wfd);
if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{ //此路径是个文件夹
StateMemo->Lines->Add("该U盘已经经过免疫,无需查杀!");
}
else
{ //此文件存在,通常可能为不正常文件
StateMemo->Lines->Add("发现可疑文件autorun.inf");
FileSetAttr(filepath,~faReadOnly); //去掉其只读属性
DeleteFile(filepath); //删除
StateMemo->Lines->Add("已删除可疑文件autorun.inf");
}
FindClose(hFind);
}
}
if(USB=='A') //如果此值没改变说明没有发现U盘
{
StateMemo->Lines->Add("没有发现可移动磁盘!");
}
return;
}
扫描U盘的代码就算完工了,下面我们开始写扫描硬盘的代码,首先当然是要查杀病毒进程,见以下代码:
int count=0; //可疑进程数量
//创建当前进程快照
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(hProcessSnap==INVALID_HANDLE_VALUE)
{
StateMemo->Lines->Add("创建进程快照失败!");
}
PROCESSENTRY32 processEntry={0};
processEntry dwSize=sizeof(PROCESSENTRY32);
//开始遍历进程快照
bool bRet=Process32First(hProcessSnap,&processEntry);
while(bRet) //如果返回不为空就继续执行循环
{ //ExtraceFileName是提取出纯文件名,去掉路径
if(ExtractFileName(processEntry.szExeFile)=="algsrvs.exe")
{
StateMemo->Lines->Add("发现可疑进程algsrvs.exe!");
//根据进程PID以完全权限打开此进程,然后强制终止
HANDLE hVirus = OpenProcess(PROCESS_ALL_ACCESS,false,processEntry.th32ProcessID);
TerminateProcess(hVirus,0);
CloseHandle(hVirus);
StateMemo->Lines->Add("可疑进程已经被结束!");
count++; //可疑进程数量加1
}
bRet=Process32Next(hProcessSnap,&processEntry);
}
CloseHandle(hProcessSnap);
if(count==0) //没找到可疑进程
{
StateMemo->Lines->Add("没有发现可疑进程!");
}
上面这段是非常经典的遍历进程的代码,大家务必要理解哦,以后想查找其他进程的话只要把其中的进程名改一下就OK了,hoho~~~。
下面开始查杀系统中存在的病毒文件,通常情况下病毒文件的分布都是有规律的,一般在系统文件夹和各个分区的根目录下,所以我们不需要进行全盘扫描,因为如果你的硬盘中的文件很多的话这可是一件相当痛苦的事情。但我们根据文件名来打开文件,通过其返回值判断文件是否存在,而没有做杀毒软件通常的查找特征码的操作,所以速度会提升不少。
为了下面的调用方便,我们先写两个独立的函数分别判断文件是否存在和删除文件,见下:
bool __fastcall TMainForm::ScanFile(char buffer[MAX_PATH])
{ //查找文件是否存在,参数为文件的完整路径名
FILE *fp;
fp=fopen(buffer,"rb");
if(fp==NULL)
{
return false;
}
StateMemo->Lines->Add("发现可疑文件"+String(buffer));
fclose(fp);
return true;
}
bool __fastcall TMainForm::DeleteVirusFile(char buffer[MAX_PATH])
{ //根据完整文件名删除文件
bool result=false;
FileSetAttr(buffer,~faReadOnly);
result = DeleteFile(buffer);
if(result==true)
{
StateMemo->Lines->Add("可疑文件"+String(buffer)+"成功被清除!");
return true;
}
StateMemo->Lines->Add("可疑文件"+String(buffer)+"清除失败!");
return false;
}
下面将会频繁地调用这两个函数,我们的重点在于快速查杀,通常情况下这样就足够了。请看代码:
if(ConfigRadioGroup->ItemIndex==0) //快速扫描
{
char filename[MAX_PATH]; //保存文件名
char filepath[MAX_PATH]; //保存文件路径
DWORD dwSize=MAX_PATH+1;
GetWindowsDirectory(filepath,dwSize);
sprintf(filename,"%s\\algsrvs.exe",filepath); //搜索Windows目录
if(ScanFile(filename)==true)
{
DeleteVirusFile(filename);
}
sprintf(filename,"%s\\msfun80.exe",filepath);
if(ScanFile(filename)==true)
{
DeleteVirusFile(filename);
}
sprintf(filename,"%s\\msime82.exe",filepath);
if(ScanFile(filename)==true)
{
DeleteVirusFile(filename);
}
sprintf(filename,"%s\\ufdata2000.log",filepath);
if(ScanFile(filename)==true)
{
DeleteVirusFile(filename);
}
sprintf(filename,"%s\\fun.xls.exe",filepath);
if(ScanFile(filename)==true)
{
DeleteVirusFile(filename);
}
//下面都一样,就不浪费版面空间了,呵呵,仅给出路径代码
sprintf(filename,"%s\\system\\algsrvs.exe",filepath); //搜索system目录
GetSystemDirectory(filepath,dwSize);
sprintf(filename,"%s\\algsrvs.exe",filepath); //搜索system32目录
}
这样就是快速扫描的代码了,至于深度扫描其实是不停地递归遍历全盘,找到可疑文件就进行删除,主要就是利用FindFirstFile()和 FindNextFile()这两个函数,每找到一个文件就判断,如果是文件则判断是否符合要求,如果是目录就进入继续递归。这个代码网上非常多,就不浪费版面空间了。
然后是搜索注册表中的相关键值,关于注册表的使用其实也很简单,我没使用API函数,因为VCL提供了一个封装好的类TRegister,使用起来非常方便,方法大致如下:
TRegistry *Reg=new TRegistry;
try
{
Reg->RootKey=HKEY_LOCAL_MACHINE;
Reg->OpenKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run",true);
Reg->DeleteValue("这里写你要删除的值");
//如果想新建一个项则可以使用OpenKey()打开,不存在的话它就会自动创建。
}
__finally
{
delete Reg;
}
在使用前记得包含头文件#include <Registry.hpp>。
OK,注册表清理过程大概就是这样了,由于这个程序加入的注册表项比较多,我杀毒的时候使用的是手工查找,不停地按F3同样很快就把有关项清理干净了,但问题是不可能把每一项的位置记录下来,所以这里只能给出删除的方法,不太完整的一点,算遗憾吧。
最后清理各分区根目录下的病毒文件,这个就非常简单了,请参考上面扫描U盘的代码,这里还更简单点。下面是内核代码:
for(szDriveName[0]='C';szDriveName[0]<'Z';szDriveName[0]++)
{ //从C到Z遍历硬盘
//使用GetDriveType判断是否为固定磁盘
if(GetDriveType(szDriveName)==3) //固定磁盘
{
//这里加入判断是否有病毒文件存在和删除其的代码
//通常只用检查根目录,所以很简单,就不多说了
char buffer[MAX_PATH];
sprintf(buffer,"%s:\\Autorun.inf",szDriveName[0]);
ScanFile(buffer);
DeleteVirusFile(buffer);
}
}
这样一个简单但又比较完整的病毒专杀程序就完工了,当然要想拿得出手我们还得花很多努力更好地完善,比如程序的容错处理,代码的优化,界面友好度等等。