您的位置:首页 > 编程语言 > C语言/C++

如何让程序自身防病毒

2016-07-13 22:26 288 查看
一、前言

计算机病毒(Computer Virus)在《中华人民共和国计算机信息系统安全保护条例》中被明确定义为“编制或者在计算机程序中插入的破坏计算机功能或者破坏数据,影响计算机使用并且能够自我复制的一组计算机指令或者程序代码”。然而伴随着互联网和计算机的快速发展,病毒的也从单纯破坏计算机功能和数据演变为以最终经济利益为驱动的功能各异的变体。作为病毒感染传播的重要途径,寄生在正常文件实现自身复制传播的方式依然为众多病毒所采用,为了避免我们自己编写的程序被病毒所感染,成为助纣为虐的工具,在这里我给大家介绍几种在编程中防止病毒感染程序自身的方法,希望能够抛砖引玉,让病毒远离我们的程序。

二、实现方法

程序防病毒的思路就是我们在编程的时候加入一些检测程序自身是否被篡改的代码,如若检测到文件被改变,则向用户提示计算机可能感染病毒的风险,然后退出程序。在这里我采用以下几种方式对程序进行自身校验,以防止被非法篡改。

(1)判断文件大小的方法

首先我想到的就是文件大小的判断,如果我们程序文件的大小超过了本身正常的长度,那么就可以断定该程序已被感染,否则程序不会发生长度变化的。这时程序显示“程序被感染”对话框后退出。写程序时我们要先将可执行文件生成出来,看看正常的大小值是多少,然后再将文件大小写入到程序代码中作为正常值进行比较,用来判断程序文件的大小是否发生变化。以下是程序实现的关键代码:

//获取自身文件名

 ::GetModuleFileName(0, my_name, sizeof(my_name));

 struct _stat ST; 

 _stat(my_name, &ST);

 //加入程序的最终大小,来判断文件是否被感染

 if(ST.st_size > 188471) 

 {

     MessageBox(NULL,"程序被感染","注意",MB_OK);

   exit(0);    //直接退出程序

 }

  

(2)通过文件副本比较法

检查文件大小的方法虽然简单实用,但是对于部分不改变宿主文件大小,直接把代码插入到PE文件中可用空闲空间的病毒来说就失去了防护作用了。对于这种情况我想可以在程序发布时提供一个拷贝的副本,后缀改成非可执行文件的后缀,在程序运行时去检查自身与副本文件是否一样,否则提示“程序被感染”对话框后退出。写程序时先将可执行程序生成出来,获得文件大小,然后再将文件大小写入到程序代码中作为循环比较次数(当然也可以用其他方法比较)。以下是程序实现的关键代码:

FILE *sfp,*bfp;

sfp=fopen(my_name,"rb");

bfp=fopen(backup_name,"rb");

int i;

 

for (i=0;i<180273;i++)

{

 if (fgetc(sfp) != fgetc(bfp))

 {

  MessageBox(NULL,"程序被感染","notice",MB_OK);

  exit(0);

 }

}

(3)通过程序的MD5值检查法

对文件做HASH摘要后进行比较,可以快速准确的发现文件哪怕是最细微的改变。MD5作为一种流行的信息摘要算法在用于确保文件信息完整一致性有着非常广泛的应用。在通过文件副本比较的方法中我们可以将文件的相互比较改成比较文件的MD5值,如果该值发生变化则可以断定程序被非法篡改了。程序编写前我们首先要找到对文件进行MD5摘要的函数。我在网上找了一圈没找到直接对文件进行MD5的C程序代码,只找到了一个对字符串做MD5摘要的类,所以我们在编程时需要引用该类,然后对要做MD5值比较的文件内容进行转换,方法是以共享只读的方式将自身文件打开,然后通过CreateFileMapping函数创建文件映射对象,再将文件映射对象映射到当前应用程序的地址空间,最后我们就可以直接调用MD5类的方法进行摘要,像处理字符串一样来处理文件的映像了。关键代码如下:

fHandle=CreateFile(filename,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

filesize=::GetFileSize(fHandle,NULL);

mHandle=CreateFileMapping(fHandle,NULL,PAGE_READONLY,0,0,NULL);

lpHandle=(DWORD)MapViewOfFile(mHandle,FILE_MAP_READ,0,0,0);

char *lpFileData=(char *)lpHandle;

MD5_CTX   md5T;   

unsigned   char   digest[16];   

md5T.MD5Update   ((unsigned   char*)lpFileData, filesize);

md5T.MD5Final   (digest); 

char s[16];

for(int  i=0;i<16;i++)   

{   sprintf((s+2*i),"%2X",digest[i]); } //格式化MD5值

通过以上代码,我们可以先后获得程序自身的MD5值和备份文件的MD5值(这里的备份文件和程序处于同一文件夹下,名称为backup),再对获得的两个文件的MD5值进行相互比较,如果值相等则说明程序正常,未被感染,可以继续向下执行,否则立即退出程序。我也考虑过是否可以不用副本的方式进行文件的MD5值比较,将正常的MD5值存在程序中当比较时直接使用,比如事先将程序自身的MD5值存到程序中,程序运行后直接计算自身的MD5值然后与存在程序中的MD5值进行比较。可仔细想想我如何实现在编代码还没有生成可执行文件的时候就获得最终程序的MD5值呢?这不和先有鸡还是先有蛋的问题一样了么?我需要在程序编写时就知道生成的可执行文件的MD5值,可是生成的可执行文件的MD5值与我编程写入的值又密切相关,根本无法获得。所以只能使用对备份文件进行MD5摘要比较的方法来进行检测了。

(4)使用MapFileAndCheckSum函数法

PE可执行文件头中有一个CheckSum双字,用于存放PE可执行文件的校验和。我们可以利用这个文件头参数来检测文件自身是否被改变过。一般的可执行文件不需要校验和,因此在普通可执行文件中CheckSun通常是0。而Windows的驱动程序则需要校验和,如果此处的值与验证的校验和不同,就会提示出错,提醒你重新下载驱动程序。根据这个原理,我们可以利用MapFileAndCheckSum函数来编写出具有防止程序被感染更改的程序。该函数原型如下:

ULONG MapFileAndCheckSumA(

IN LPSTR Filename,

OUT LPDWORD HeaderSum,

OUT LPDWORD CheckSum

);

参数意义:

Filename 指定文件名的字符串的指针,就是自身文件名

HeaderSum原始校验和变量的指针,有错误时它是零值。

CheckSum计算后的校验和的变量指针。

返回值:

如果函数成功, 函数返回值是CHECKSUM_SUCCESS ;

如果函数失败,函数返回值为下列值之一:

CHECKSUM_OPEN_FAILURE:不能打开文件;

CHECKSUM_MAP_FAILURE:不能创建文件的映射文件;

CHECKSUM_MAPVIEW_FAILURE:不能映射文件的观看;

CHECKSUM_UNICODE_FAILURE :不能将文件名称转换为UNICODE。

程序代码如下:

//取程序的文件名

GetModuleFileName(GetModuleHandle(NULL),buf,512);

//调用MapFileAndCheckSum 取该文件的校验和if(CHECKSUM_SUCCESS!=MapFileAndCheckSum(buf,

&head_check_sum,&check_sum))

{ MessageBox(0,"检查出错,检查未完成","错误",MB_OK);

return 0;}

// 分析结果

if(head_check_sum!=check_sum)

{MessageBox(0,"这程序已经被非法改动,可能您的系统已经被病毒感染","出错提示",MB_ICONWARNING);}

return 0;}
需要注意的是,如果想使普通的PE可执行文件具有这种防止病毒感染的能力,需要在程序编写时作以下设置:连上imagehlp.lib这个库,然后在Project(工程)->Settings(设置)->Link(连接)中去掉Generate debug info(产生调试信息)和Link incrementlly选项,再选择Link(连接)->Category(分类)组合框的Customize(自定义),去掉Use
program database(应用程序数据库)选项,最后在Project Options(工程选项)中加入"/release",这样这个程序就具有防病毒感染和修改的功能了。

三、总结

   通过以上四种方法,我们可以有效地防止病毒对我们程序的修改和感染。每种方法都有其各自的特点和适应的情况,在编程中可以根据不同情况选择合适的方法。这些方法比较简单,哪位朋友有更好的方法希望能够共享,大家多多交流。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++