注:本文已发表在<黑客防线>2008年第1期,转载请注明出处.

在第11期的《黑客防线》中,我那篇关于algsrvs病毒专杀的文章中有点不太完美的地方,就是没有把清理注册表那一部分写完整,一个原因就是我在那里说的因为当时我已经把病毒清理干净了,没有记录下每一个相应键值的位置;还有一个原因就是就算我记录下来了,也是一件相当麻烦的事情,因为病毒在注册表中写入的信息相当地多,大概有几十处,这样一个一个删还不把人累死?

当然也不是没有办法,我今天就用一种比较简单的思路来进行演示:首先完整枚举所有项,检查其键值是否被病毒修改过,然后进入子项中递归调用此函数完成遍历注册表的功能。

为了程序的通用性,今天我就不用VCL库中的Registry类了,改用Windows操作系统提供的正宗API,这样大家就可以把它完美地嵌入到自己的程序中了。

首先来讲一点基础知识,使没有编程操作过注册表的菜友们也能顺利上手。

注册表有五大子键,这我就不废话了,今天我们只拿其中比较重要的一个HKEY_LOCAL_MACHINE来演示,需要遍历注册表的话只需要把函数简单修改下调用五次就没问题咯。我们在注册表中某个地方点击右键,选择“新建”,可以看到有以下几种数据类型:字符串值、二进制值、DWORD值、多字符串值、可扩充字符串值。最常用的也是注册表中子项的默认值就是字符串值,它的内部名称为REG_SZ。

关于注册表编程的资料通常都很零散,所以通常我们最好的参考书就是MSDN了,在MSDN的索引里输入Reg就可以显示出所有以Reg开头的函数,前面那些基本就是跟操作注册表有关的,RegOpenKeyEx,RegCloseKey,RegDeleteValue、RegEnumKeyEx、RegEnumValue、RegQueryValueEx、RegSetValueEx这几个是我们重点需要的。

首先我们来看一下删除病毒键值的方法,为避免误删除,我们先自己建立一个子项:HKEY_LOCAL_MACHINE\SOFTWARE\grayfox,选中它后在右边的空白区域点右键,“新建”——“字符串值”——“test”,双击“test”,在“数值数据”里输入“test1,test2,test3”。我们假设test是启动项,test1、test2是本来的启动程序,病毒又向其中添加了一个test3,我们的目的就是把使其还原为test1,test2。这里要注意的是我们是不能直接使用RegDeleteKey将其删除的,如果里面只有test3这个值的话是可以的,但如果还有其他值的话需要使用RegSetValueEx重新设置。

现在我们来使用VC 6.0建立一个控制台程序测试效果,代码如下:

#include <stdio.h>

#include <windows.h>

void main()

{

HKEY hKey = NULL;

DWORD rc;

rc=::RegOpenKeyEx(HKEY_LOCAL_MACHINE,"software\\grayfox",0,

KEY_ALL_ACCESS,&hKey);

if( rc == ERROR_SUCCESS )

{

unsigned char buffer[MAX_PATH]="\0";

DWORD type = REG_SZ;

DWORD size = sizeof(buffer);

if(RegQueryValueEx(hKey,"test",NULL,&type,(LPBYTE)buffer,&size)==ERROR_SUCCESS)

{ //先读取原内容保存到buffer中

printf("%s\n",buffer);

char *lstr;

lstr = strstr((char *)buffer,"test3"); //检查是否有test3这个值

if(lstr != NULL) //如果有则进入处理

{

printf("Find!\n");

if(strchr((char *)buffer,',') == NULL) //检查是否有逗号

{ //无逗号说明只有这一个值,可直接删除

RegDeleteValue(hKey,"test");

}

else

{ //有逗号不能直接删除,需重新设置值

int result = (int)lstr - (int)buffer; //找到病毒名字符串所在位置

buffer[result - 1] = '\0'; //从这里将后面截断,因为病毒通常都是将自己加入后在最后面

printf("New Buffer:%s\n",buffer);

sprintf((char *)buffer,"%s",buffer);

RegSetValueEx(hKey,"test",0,REG_SZ,buffer,sizeof(buffer));

}

}

}

}

else

{

printf("Can't Open The Key!\n");

}

RegCloseKey(hKey);

}

代码其实不长,函数也不多,很容易看懂,太多的注释反而会影响整体思路。下面的代码都侧重于搜索,而对搜索到符合条件的值如何处理没有给出实际代码,所以上面这段代码请务必领会。

我们运行下看看,果然被修改成了test1,test2,我们再把这两个值改成test3,然后重新运行程序,可以看到由于只有一个值,这个键值被直接删除了,hoho~~命中目标!

当然,这段代码其实并不完善,因为假如里面刚好有个值为abctest3de的话,不是被直接KILL就是该被改成abc了,完全不符合我们原来的设想了,这个问题就交给大家发挥自己的聪明才智来解决了。

下面我们来演示枚举子项和枚举键值。请看代码:

#include <windows.h>

#include <stdio.h>

#define SUBKEYS 1 //决定是枚举子项还是键值

void main()

{

HKEY hKey = NULL,h = NULL;

char str[MAX_PATH];

DWORD num = sizeof(str),index = 0,rc;

posted on 2008-03-02 14:47  lovecl  阅读(276)  评论(0)    收藏  举报